What is the default parameter for AUTOLOAD in Perl?-Collection of common programming errors
Using Autoload is inherently difficult. If you want a solid object system that makes accessors for you then please use Moose, Mouse, Moo, or just loop over your fields and install the accessors yourself:
BEGIN {
my @fields = qw/foo bar baz/;
for my $field (@fields) {
no strict 'refs';
# install a closure in the package stash.
*{ __PACKAGE__ . "::" . $field } = sub {
my $self = shift;
$self->{$field} = shift if @_;
return $self->{$field};
};
}
}
If a class that can AUTOLOAD
encounters an undefined method, the AUTOLOAD
sub is called with the arguments of the missing sub. The fully qualified name of the requested sub is passed in the $AUTOLOAD
package variable.
A typical Autoload sub would look like:
use Carp;
my %fields_allowed = map {$_ => 1} qw/foo bar baz/;
sub AUTOLOAD {
my $field = our $AUTOLOAD;
$field =~ s/.*:://; # strip the package name
$fields_allowed{$field}
or croak qq(Can't locate object method $field via package "@{[__PACKAGE__]}");
my $self = shift;
$self->{$field} = shift if @_;
return $self->{$field};
}
There remain two problems:
- When the reference count of an object drops to zero, or when a thread terminates, the
DESTROY
method is called on the object if it provides one. We can prevent autoloading ofDESTROY
by providing an empty implementation:sub DESTROY {}
. - We can ask any object if it can perform a certain method, like
say "Good dog" if $dog->can("roll")
. Therefore, we have to overridecan
to support our autoloading. Thecan
method is useful for safe duck typing. Every object inherits fromUNIVERSAL
, which provides default implementations forcan
andisa
.
The contract of can
is that it takes the name of a method. It will return undef
when the object cannot perform the method, or a code reference to that method if it can. A suitable implementation would be
sub can {
my ($self, $name) = @_;
# check if it's a field of ours
if ($fields_allowed{$name}) {
return sub {
my $self = shift;
$self->{$name} = shift if @_;
return $self->{$name};
};
}
# Ask SUPER implementation of can if we can do $name
if (my $meth = $self->SUPER::can($name)) {
return $meth;
}
return; # no method found
}
We can now simplify AUTOLOAD
to
sub AUTOLOAD {
my $field = our $AUTOLOAD;
$field =~ s/.*:://; # strip the package name
my $code = $self->can($field)
or croak qq(Can't locate object method $field via package "@{[__PACKAGE__]}");
goto &$code; # tail call; invisible via `caller()`.
}
This is a lot of complexity to get right. Verdict: Don’t use Autoload because you think it might be less work. It never is. It is quite useful for implementing a proxy pattern, but that is a bit advanced.
I urge you to dabble around with OO basics, and the Moose object system, before diving deep into Perl’s unique and strange features.
Originally posted 2013-11-09 21:09:20.