[Mpls-pm] Dumb Question...Module Method - Dual Name

Joshua ben Jore twists at gmail.com
Tue Oct 25 16:54:50 PDT 2005


On 10/21/05, Ian Malpass <ian at indecorous.com> wrote:
>   sub AUTOLOAD {
>     $AUTOLOAD =~ /.*::(.+)/;
>     my $method = $1;
>     if ( $_[0] and ( ref $_[0] eq __PACKAGE__ or $_[0] eq __PACKAGE__ ) ) {
>       die "Unknown method: $method";
>     } elsif ( $method =~ /^eg(.+)/ and __PACKAGE__->can( $1 ) ) {
>       return __PACKAGE__->$1( @_ );
>     } else {
>       die "Unknown subroutine: $method";
>     }
>   }

Ian,
You were doing so well that I didn't want to interrupt. I'd like to
make one small note here. If you're tempted to install methods from
within AUTOLOAD, be aware that you're invalidating perl's method
cache. On perlmonks.org, suggestions to use AUTOLOAD are often
followed by clever suggestions to have AUTOLOAD remove itself by
installing the looked-up function into the symbol table. This is fine
except that it causes the global method cache to get invalidated.

When a method is called and it isn't in the cache, perl does the long
job of walking around @ISA to find the right foo() function. Once
that's done, perl makes a note of the function it found and then
doesn't have to look at @ISA again. This is great - it means that
after the first method call its as fast as a regular function call.
Here's a bit of perl code that approximates the idea of what happens.

my $method = $cache{ ref $o }{ 'foo' } ||= lookup_via_isa( ref $o, 'foo' );
$o->$method( ... );

# The fast, cached way
my $method = $cache{ ref $o }{ 'foo' };

# The slow, lookup way
my $method = lookup_via_isa( ref $o, 'foo' );

Anytime you do something that increments the internal
PL_sub_generation variable, the cache is invalidated. In a general
sense, those things are adding or removing packages or named functions
and editing any @ISA. That is, stuff that could affect whether the
meaning of any or all named function calls has changed.

*foo = *bar
*foo = \ &bar
{ local *foo = *bar }
{ local *foo = \ &bar }
eval 'sub foo { ... }'
eval 'package Foo; %Foo::something_new = ()' # Maybe?
@ISA = ...
@Something::Else::ISA = ...
delete $main::{foo}

If you do all your method generation up front, the cache will only be
invalid once because of your actions. If you do it on the fly, you'll
be invalidating it during runtime.

I keep meaning to instrument PL_sub_generation and benchmark how much
this actually affects stuff but haven't gotten around to it.

Josh


More information about the Mpls-pm mailing list