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 of DESTROY 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 override can to support our autoloading. The can method is useful for safe duck typing. Every object inherits from UNIVERSAL, which provides default implementations for can and isa.

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.