{ package Foo; sub foo { ... } # autoloads bar() # autoloads baz() } { package Bar; @ISA = Foo::; # autoloads foo() # autoloads bar() } #### my $code = $obj->can('foo'); $obj->$code(...) #### $obj->foo(...) #### AUTOLOAD { ...; if (should_autoload($method)) { ... } else { croak("No method $method ..."); } } #### AUTOLOAD { ...; if (should_autoload($method)) { ... } elsif (my $code = $self->can('SUPER::AUTOLOAD')) { goto &$code; } else { croak("No method $method ..."); } } #### AUTOLOAD { my $self = $_[0]; # Not shift, using goto. my $method = ...; if (my $code = _autoloaded($self, $method)) { goto &$code; } elsif (my $next = next_autoload($self)) { goto &$next; } elsif ($method eq 'DESTROY') { # If people do $obj->DESTROY and there's no # DESTROY available then they'll be surprised. # Just as surprised I am that they call DESTROY # explicitly. return; } else { croak(...); } } #### sub can { my ($self, $method) = @_; # Not shift, using goto. # The call to UNIVERSAL::can() should be inside an eval EXPR # to get caller info right for when $method =~ /^SUPER::/, # if can() is exported (see Class::AUTOCAN below). my $universal = UNIVERSAL::can($self, $method); if (not defined $universal) { if (my $code = _autoloaded($self, $method)) { return $code; } } if (my $next = $self->next::can) { goto &$next } return $universal; # May be undefined. } #### use Class::AUTOCAN sub { my $self = shift; my ($method) = @_; if ($method =~ /^auto_/) { return sub { my $self = shift; return "$self called $method"; }; } return; }; #### Class::AUTOCAN->install( target => $pkg, code => sub { ... }, );