Class::MethodMaker(3)
π Class::MethodMaker(3) π
okay bestie, this is the User Contributed Perl Documentation glow-up for Class::MethodMaker(3) β and it's giving βI write my own accessors and I'm not sorryβ energy. Buckle up. π
πΈ NAME πΈ
Class::MethodMaker - Create generic methods for OO Perl
β¨ SYNOPSIS β¨
use Class::MethodMaker
[ scalar => [qw/ foo bar baz /],
new => [qw/ new /] ,
];
π¦ DESCRIPTION π¦
okay so this module solves the very real problem of having to keep writing accessor methods for your objects that do standard tasks. Like, we get it, nobody wants to hand-write the same little methods forever. π
The argument to use is an arrayref, arranged as pairs: the "keys" are the names of types of generic methods generated by MethodMaker, and the "values" tell MethodMaker what methods to make.
To override any generated methods, it is sufficient to make sure the overriding method is defined when Class::MethodMaker is called. But heads up, bestie: the use keyword introduces a BEGIN block, so you may need to define (or at least declare) your overriding method in a BEGIN block.
π«Ά this is the classic Perl timing thing β define/declare early, or your override may not be there when MethodMaker comes knocking.
π Simple Use π
A simple class made with Class::MethodMaker looks like this:
package MyClass;
use Class::MethodMaker
[ scalar => [qw/ name /],
new => [qw/ new /],
];
This creates a class, of which new instances may be created using new, each with a single scalar component called name. name may be queried and (re)set using the methods name, name_reset and name_isset:
package main;
my $m = MyClass->new;
my $n;
$\ = "\n";
print $m->name_isset ? "true" : "false"; # false
$m->name("foo");
$n = $m->name;
print defined $n ? "->$n<-" : "*undef*"; # ->foo<-
print $m->name_isset ? "true" : "false"; # true
$m->name(undef);
$n = $m->name;
print defined $n ? "->$n<-" : "*undef*"; # *undef*
print $m->name_isset ? "true" : "false"; # true
$m->name_reset;
$n = $m->name;
print defined $n ? "->$n<-" : "*undef*"; # *undef*
print $m->name_isset ? "true" : "false"; # false
The available component types are scalar, array, hash. Certain non-data-type utilities are also provided: new, for constructors, deep_copy and copy for object copies, and abstract for creating abstract methods.
Each of the components take common options. These include:
-staticβ for per-class rather than per-instance data-typeβ to restrict the data stored to certain types (e.g., objects of a certain class)-forwardβ to forward (proxy) given methods onto components-default/-default_ctorβ to set default values for components-tie_classβ to tie the storage of a data type to a given class-read_cb/-store_cbβ to call user-defined functions on read/store (without the overhead/complexity of ties; and allowing callbacks on existing tie classes)
π Detailed Use π
Class::MethodMaker installs components into a class, by means of methods that interrogate and amend those components. A component β sometimes referred to in other documentation as a slot β is a group of one or more attributes (variables) that are associated with an instance of a class (sometimes called an object), or occasionally a class itself (often referred to as a static component). A component is intended as a cohesive unit of data that should only normally be interrogated or set through the methods provided.
Given an instance of a class where each instance represents a car, examples of components are the make and model (each of which would be a simple scalar, a string), the engine (a simple scalar, an instance of Engine::Combustion), and the wheels (an array of instances of Wheel). Note that the wheels form one component, an array. Of course, the implementor might instead choose to use four components, each being a scalar wheel.
To have the components created, the main use of Class::MethodMaker is to specify the type (data-structure) and name of each component to the import method of Class::MethodMaker:
package MyClass;
use Class::MethodMaker
[ scalar => 'name',
new => [qw/ new /],
];
In this example, the import is called implicitly via the use statement. The components are installed in the package in effect where the import is called. The argument to import is arranged as pairs, where the first of each pair is the type of the data-structure, the second is the arguments for that data-structure; in the most simple case, the name of a component to install using that data-structure. The second of the pair should be an arrayref if not a simple name.
Data-structures may be repeated in the call:
use Class::MethodMaker
[ scalar => 'name1',
new => [qw/ new /],
scalar => 'name2',
];
It is an error to attempt to install a two or more components with the same name twice. Not the vibe. π«
Options may be given to data structures to amend the nature and behaviour of the components created. Some options are common across all data structures (e.g., static) whilst some are specific to their respective data structures. Option syntax is laid out in detail below. In simple, options are provided by way of hashrefs from option name to option value. Options and component names are order-sensitive; options appearing after a component do not affect that component. Options only apply to the data-structure to which they are specified. Boolean options (e.g., static) may be abbreviated to -option to set, !option to unset, without a hashref.
use Class::MethodMaker
[ scalar => [+{ -type => 'File::stat' }, qw/ -static name /],
new => 'new',
];
There are also non-data-structure methods that may be created by Class::MethodMaker. new is an example of one such value; it instead causes a standard new method to be created for the calling class. The arguments and options syntax remains the same, but many options clearly do not apply (e.g., type for new).
π Interaction with Superclasses π
Basically, Class::MethodMaker takes no notice of class hierarchies. If you choose to install a component x in a class B that is a subclass of class A that already has a component x, then the methods addressing x in B will simply override those in class A in the usual fashion. Class::MethodMaker takes no special action for this situation. This is a feature. π
π Option Syntax π
The arguments to Class::MethodMaker are passed in a single arrayref, as pairs, with the first of each pair being the name of the data-structure, and the second being the arguments to that structure.
use Class::MethodMaker
[ scalar => 'name',
new => [qw/ new /],
];
The second of the pair may in the most simple case be a single scalar that is the name of a component to use.
use Class::MethodMaker
[ scalar => 'bob', ];
For anything more complex, the second argument must itself be an arrayreference. Simple names within this arrayreference are again taken as component names to use; in the following example, both foo and bar scalar components are created:
use Class::MethodMaker
[ scalar => [qw/ foo bar /], ];
Options to the data-structure, to change the behaviour of the component, or methods available, etc., are specified by the presence of a hash reference in line with the component names. Each key of the hashref is the name of an option; the corresponding value is the option value. Option names are easily recognized by a leading hyphen (-) (or leading exclamation mark, !). The options affect only the components named after the option itself. In the following example, foo is non-static (the default), whilst bar is a static:
use Class::MethodMaker
[ scalar => ['foo', { -static => 1 }, 'bar'], ];
Naturally, options may be altered by later settings overriding earlier ones. The example below has exactly the same effect as the one above:
use Class::MethodMaker
[ scalar => [{ -static => 1 }, 'bar', { -static => 0 }, 'foo'], ];
Options that are boolean (on/off) valued, such as -static, may be specified external to any hashref as -optionname to set them on and !optionname to set them off. The example below has exactly the same effect as the one above:
use Class::MethodMaker
[ scalar => [ qw/ -static bar !static foo /], ];
Options that take a value, e.g., -type, must be specified within a hashref:
use Class::MethodMaker
[ scalar => [ +{ type => 'File::stat' }, 'bob' ], ];
Options affect is limited by the scope of the nearest enclosing arrayref. This particularly means that for multiple invocations of a data structure type, options on earlier invocations do not affect later ones. In the following example, foo is non-static (the default), whilst bar is a static:
use Class::MethodMaker
[ scalar => [ qw/ -static bar /],
scalar => [ 'foo' ],
];
This is true even if later invocations do not use an arrayref. The example below has exactly the same effect as the one above:
use Class::MethodMaker
[ scalar => [ qw/ -static bar /],
scalar => 'foo',
];
Arrayrefs may be employed within a set of arguments for a single data-structure to likewise limit scope. The example below has exactly the same effect as the one above:
use Class::MethodMaker
[ scalar => [ [ qw/ -static bar / ], 'foo' ],
];
π§ Method Renaming π§
Methods may be renamed, by providing options that map from one generic name to another. These are identified by the presence of a * in the option name.
The example below installs component a as a scalar, but the method that would normally be installed as a_get is instead installed as get_a, and likewise set_a is installed in place of a_set.
use Class::MethodMaker
[ scalar => [ { '*_get' => 'get_*',
'*_set' => 'set_*', },
'a' ],
];
π Default & Optional Methods π
Class::MethodMaker installs a number of methods by default. Some methods, considered to be useful only to a subset of developers, are installed only on request. Each method is marked in the text to state whether it is installed by default or only upon request.
To request that a non-default method is installed, one needs to rename it (even possibly to its normal name). So, to install the *_get method for a scalar attribute (as *_get), the syntax is:
package MyClass;
use Class::MethodMaker
[ scalar => [{'*_get' => '*_get'}, 'a'] ];
The method may be installed using a non-default name using similar syntax:
package MyClass;
use Class::MethodMaker
[ scalar => [{'*_get' => 'get_*'}, 'a'] ];
The client may choose to not install a default method by renaming it to undef:
use Class::MethodMaker
[ scalar => [{'*' => undef }, 'a'] ];
quick note before we keep going, bestie: Class::MethodMaker will not install a method in place of an existing method, so if the intent is to not install a default method because the client has their own version, an alternative to the above is to define the client version before calling Class::MethodMaker. no cap, that ordering matters π
πΈ Naming & Method-Design Conventions πΈ
The standard method names are designed with predictability and class extendibility in mind. iconic behavior, honestly β¨
π Naming π
For any component x that Class::MethodMaker creates, the method names are always x or x_*. This enables predictability, for you do not need to remember which methods are named x_* and which *_x, and also you can name methods that you create by avoiding prefixing them with x, and so avoid any clash with Class::MethodMaker-generated methods (even if Class::MethodMaker is upgraded with shiny new extra methods). Class::MethodMaker users may rename methods (see "Method Renaming"). π«Ά
For any data-structure component (scalar, array, hash, etc.) x that Class::MethodMaker creates, the method x sets the value of that component: i.e., overriding any existing value, not amending or modifying. E.g., for array components, x does not push or pull values but all old values are removed, and new ones placed in their stead:
package MyClass;
use Class::MethodMaker
[ array => 'a',
new => 'new',
];
package main;
my $m = MyClass->new;
$m->a(4,5);
print join(' ', $m->a), "\n"; # 4 5
$m->a(6,7);
print join(' ', $m->a), "\n"; # 6 7
The method returns the new value of the component:
print join(' ', $m->a(8,9)), "\n"; # 8 9
Note that calling the method with an empty list does not reset the value to empty; this is so that normal lookups work on the method (i.e., if
$m->a
emptied the component, then
@a = $m->a
would always give an empty list: not that useful. π
π Set/Unset π
Each data-structure component has the concept of being set/unset as a whole, independent of individual members being set. Each component starts life unset (unless a default or default option or tie class has been supplied), and is becomes set by any assignment. The component is then reset with the *_reset method. Thus it is possible to distinguish between a component that has been set to an explicitly empty value, and one that has not been set (or been reset). This distinction is analogous to the distinction in hashes between a missing key and a key whose value is undef. π¦
package MyClass;
use Class::MethodMaker
[ new => 'new',
scalar => 'x',
];
package main;
my $m = MyClass->new;
$\ = "\n";
print $m->x_isset ? "true" : "false"; # false; components start this way
my $x = $m->x;
print defined $n ? "->$n<-" : '*undef*'; # *undef*
print $m->x_isset ? "true" : "false"; # false; reading doesn't set
$m->x(undef);
$x = $m->x;
print $m->x_isset ? "true" : "false"; # true;
print defined $n ? "->$n<-" : '*undef*'; # ->foo<-
$m->x("foo");
$x = $m->x;
print $m->x_isset ? "true" : "false"; # true; undef is valid value
print defined $n ? "->$n<-" : '*undef*'; # *undef*
$m->x_reset;
$x = $m->x;
print defined $n ? "->$n<-" : '*undef*'; # *undef*
print $m->x_isset ? "true" : "false"; # false
It is not an error to query the value of an unset component: the value is undef. Querying (any passive command, or pure function) an unset component does not cause it to become set; only assigning (any active command, or procedure) changes the set status of a component. lowkey important π
NOTE THAT lvalues are still experimental (as of perl 5.8.0), and so their implementation may change or disappear in the future. Note that lvalue use defeats type-checking. This may be considered a bug, and so may be fixed if possible at some point in the future. β οΈ
π¦ Other Design Considerations π¦
Further design goals for Class::MethodMaker version 2:
Consistency of Options
The options passed to components are now handled in a single place, to try to be phrased consistently. As many options as possible are common to all data-structures. β¨
Flexibility
It is intended that all common class-construction options are supported across all data-types, so that e.g., defaults, ties, typing may be used with your data-structure of choice, and combined. π
Speed
The methods are intended to be as fast as possible, within other constraints outlined here. π₯
β¨ Options to "use"/"import" β¨
-target_classβ by default, the target class is determined to be the last (latest) class in the call stack that is not aClass::MethodMaker::Enginesubtype. This is what is wanted 99% of the time, and typical users need not worry. However, the target class may be set explicitly in the call touse/import:
use Class::MethodMaker
[ -target_class => 'X',
scalar => [qw/ a /],
-target_class => 'Y',
scalar => [qw/ b /],
];
Note that the -target_class option is order sensitive: it affects only components requested after it in the call to use/import. As shown, the same call may handle specify multiple target classes. Any components requested before the first -target_class are created in the default-determined class, as outlined above. π
Setting the target class in this way does not persist over multiple calls to use/import. A subsequent call to either will use the default-determined class as target (unless again overridden by -target_class). periodt π
π Standard Options for Data-Structure Components. π
The following options are observed by all data structure components (scalar, array, hash). iykyk π
-staticβ this option causes components to hold class-specific, rather than instance-specific values. Thus:
package MyClass;
use Class::MethodMaker
[ scalar => [qw/ -static s /], ];
package main;
my $m = MyClass->new;
my $n = MyClass->new;
$m->a(4,5);
print join(' ', $m->a), "\n"; # 4 5
print join(' ', $n->a), "\n"; # 4 5
$n->a(6,7);
print join(' ', $n->a), "\n"; # 6 7
print join(' ', $m->a), "\n"; # 6 7
-typeβ takes the name of a class, and checks that all values assigned to the component are of the appropriate type (usesUNIVERSAL::isa, so subtypes are permissible). π¦
use Class::MethodMaker
[ scalar => [{ -type => 'File::stat' }, 'st' ]];
-forwardβ this option takes as value an arrayref (or a simple scalar). The values specify a list of methods that when called on an instance of the target class, are "forwarded on" to the given component. For example,
package X;
use Class::MethodMaker
[scalar => [{ -type => 'File::stat',
-forward => [qw/ mode size /], },
'st1',
],
])},
any call of mode or size on an instance of X will simply call the method of the same name on the value stored in the component st1, with the same arguments, and returns the value(s) of this call. β¨
Forwarding only applies to the first named component (since the methodname is fixed, without the a componentname part). This is because the components are installed in the order in which they are created, and Class::MethodMaker never overwrites a pre-existing method. So, in the following example, mode and size forward to the st1 component, and read forwards to the st2 component.
package MyClass;
Class::MethodMaker->import([scalar =>
[{ -type => 'File::stat',
-forward => [qw/ mode
size /],
},
qw( st1 ),
{ -type => 'IO::Handle',
-forward => 'read', },
qw( st2 ),
]])},
Forwarding a method to a component of composite data type (e.g., array, hash) causes the method to be mapped over the values of that component. The returned value is appropriate to the component type; so a method forwarded to an array will return a list, like the array that is the component, but with each value being the instead result of applying the forwarded method to the corresponding value of the array. π«Ά
The following code populates the @sizes array with the sizes of /etc/passwd, /etc/group, in that order.
package main;
my $m = MyClass->new;
$m->st1("/etc/passwd", "/etc/group");
my @sizes = $m->size;
Calling the forwarding method in a scalar context will get the same results, but as an arrayref:
my $sizes = $m->size; # [ 921, 598 ] for example
Likewise, forwarding to a hash component will return a hash from original key to result of method on the corresponding component, or an equivalent hashref in scalar context. π
-defaultβ takes a simple value; must be eitherundefor an instance of the appropriate type if-typehas also been specified. Whenever a component is new or reset, its value(s) default to the value given. Hence*_issetwill always return true for that component. For compound data-structures, the default applies to the each element of the structure, not the compound itself. So, for array structures, the default applies to each element of the array, not the array itself. πΈ
use Class::MethodMaker
[ scalar => [{ -default => 7 }, 'df1' ]];
It is an error to specify the -default option and the -default_ctor option simultaneously. no cap, pick one β οΈ
-default_ctorβ takes a coderef to call to generate the default value. This is called the first time a value is required, and afterwards whenever reset is called. The subr is called with one argument, which is the object upon which the component exists (or the name of the class upon which the component is created, if the call is made on the class). π
use Class::MethodMaker
[scalar => [{ -default_ctor => sub {
Y->new(-3);
},
'df2',
{ -type => 'Y',
-default_ctor => 'new' },
'df3',
]
];
If the -type option is in effect, then the value can be a simple value β and that value is taken to be the name of a method to call on the class specified by -type. β¨
π¨ Error alert: it is an error to specify the-defaultoption and the-default_ctoroption simultaneously, bestie. Not allowed. No cap. π«
π -tie_class
Okay so first, hereβs the whole audit-trail example, because watching the tie calls pile up is honestly iconic:
# @z is an audit trail
my @z;
package W;
use Tie::Scalar;
use base qw( Tie::StdScalar );
sub TIESCALAR { push @z, [ 'TIESCALAR' ]; $_[0]->SUPER::TIESCALAR }
sub FETCH { push @z, [ 'FETCH' ]; $_[0]->SUPER::FETCH }
sub STORE { push @z, [ STORE => $_[1] ]; $_[0]->SUPER::STORE($_[1]) }
sub DESTROY { push @z, [ 'DESTROY' ]; $_[0]->SUPER::DESTROY }
sub UNTIE { push @z, [ UNTIE => $_[1] ]; $_[0]->SUPER::UNTIE($_[1]) }
package X;
Class::MethodMaker->import([scalar =>
[{ -type => 'File::stat',
-tie_class => 'W',
-forward => [qw/ mode
size /],
},
qw( tie1 ),
new => 'new',
]]);
This option takes a simple value as its argument, and that value is taken to be the name of a class that is tied to the storage for the component. Like, for an array component, you need a class that implements the API for tied arrays β peep Tie::Array for more info on that. Same energy for scalar components, hash components, etc. π
And note the important lil detail: itβs the component that is tied, not the data items.
Now watch the audit trail do its thing:
package main;
my $x = X->new;
# @z is empty
my $stat1 = stat "/etc/passwd";
my $stat2 = stat "/etc/group";
$x->tie1($stat1);
# @z is (['TIESCALAR'], ['STORE', $stat1])
my $y = $x->tie1;
# $y is $stat1
# @z is (['TIESCALAR'], ['STORE', $stat1], ['FETCH'])
$x->tie1($stat2);
# @z is (['TIESCALAR'], ['STORE', $stat1], ['FETCH'], ['STORE', $stat2])
$x->tie1_reset;
# @z is (['TIESCALAR'], ['STORE', $stat1], ['FETCH'], ['STORE', $stat2],\
# ['DESTROY'])
π§΅ -tie_args
package X;
Class::MethodMaker->import
([scalar => [{ -tie_class => 'V',
-tie_args => [enum => [qw/A B C/],
default => 'B'],
},
qw( tie2 ),
]]);
This option takes an array reference, and its members get passed as arguments to any tie invoked on the component β by virtue of -tie_class. If -tie_class is not in force, this whole thing is ignored. Itβs just sitting there. No thoughts, head empty. π«
Convenience alert: you can pass a single argument directly instead of embedding it in an array ref β unless that arg is an array ref itself... then nope, wrap it. π
π -read_cb
The implementation of this option is incomplete. (Not me. The option. π)
package MyClass;
use Class::MethodMaker
[ scalar => [{ -read_cb => sub { ($_[1]||0) + 1 } }, 'rcb1' ]
new => 'new';
];
This option takes a coderef as its argument, and that coderef is called whenever a value is read. It gets two arguments: the instance upon which the method was called, and the value stored in the component. Whatever the coderef returns is the value passed to the caller of the method as the component value. So the example above adds one to whatever the stored value is. One crucial note: the value is returned to the callee, but it is not stored in the object. Donβt get it twisted. π
package main;
my $m = MyClass->new;
$m->rcb1(4);
my $n = $x->rcb1; # 5
my $n = $x->rcb1; # 5
π₯ -store_cb
The implementation of this option is incomplete. Again. We stay silly. π
package MyClass;
use Class::MethodMaker
[ scalar => [{ -store_cb => sub { $_[1] + 1 } }, 'scb1' ]
new => 'new';
];
This option takes a coderef as its argument, and that coderef is called whenever a value is stored. It gets four arguments: the instance upon which the method was called, the value to store in the component, the name of the component, and the previous value of the component β if any; if the given element of the component was previously unset, only three arguments are passed.
The return value of the coderef is the value that actually gets stored in the component. So the example above stores 1 greater than the value passed in. Math ate. π₯
package main;
my $m = MyClass->new;
$m->scb1(4);
my $n = $x->scb1; # 5
Generally, store callbacks are cheaper than read callbacks, because values are read more often than they are stored. But that is a generalization. YMMV, bestie. πΈ
π§ͺ EXPERIMENTAL & COMPATIBILITY notes
Some new facilities may be marked as EXPERIMENTAL in the documentation. These facilities are being trialled, and whilst it is hoped that they will become mainstream code, no promises are made. They may change or disappear at any time. Caveat Emptor. The maintainer would be delighted to hear any feedback, particularly regarding such facilities β be it good or bad β so long as it is constructive. π«Ά
Some old facilities may be marked as COMPATIBILITY in the documentation. These facilities are being maintained purely for compatibility with old versions of this module, but will ultimately disappear. They are normally replaced by alternatives that are considered preferable. Please avoid using them, and consider amending any existing code that does use them not to. If you believe that their removal will cast an unacceptable pall over your life, please contact the maintainer. π
π SEE ALSO
Class::MethodMaker::EngineClass::MethodMaker::scalarClass::MethodMaker::arrayClass::MethodMaker::hashClass::MethodMaker::V1Compat
β¨ Thatβs the whole manual page, bestie! Source/version: perl v5.42.0; date: 2025-07-25. Go forth and slay your objects. π
π
π¦ where this page comes from
- fedora 43: perl-Class-MethodMaker 2.25-4.fc43 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms