bsb has asked for the wisdom of the Perl Monks concerning the following question:

I'm using AUTOLOADed accessors in a base class and
currently it installs the accessor in the symbol table:

sub AUTOLOAD { ... *{$AUTOLOAD} = sub { ... }; goto &$AUTOLOAD; }

However, I think that code installs it into each sub-class. Installing it in the base class would be better and easy enough, but I'm more concerned about whether I should be doing it at all under mod_perl. According to my "mod_perl guide" brain-washing, you should avoid importing symbols to save memory. So why not just do it in AUTOLOAD? (performance vs memory???)

sub AUTOLOAD { my($attr) = $AUTOLOAD =~ /^.*::(.+)$/; return $_->{$attr}; }

I really should just do some testing...

This code isn't in production so can be changed freely.

Thanks, Brad

Replies are listed 'Best First'.
Re: AUTOLOAD & mod_perl memory
by perrin (Chancellor) on Dec 03, 2002 at 05:06 UTC
    It depends. If you don't call these very often, leave them as AUTOLOADs. If you do call them often, build them automatically in a BEGIN block. Why? So you can load them in startup.pl and share the memory between processes.
      Thanks. That's a good point.

      I need an AUTOLOAD since the attribute list can change at runtime. But you're right, I should define the common and repeatedly called accessors a compile time.

      Thanks, Brad

Re: AUTOLOAD & mod_perl memory
by pike (Monk) on Dec 03, 2002 at 13:43 UTC
    I don't think that you will build the methods for all subclasses, because AUTOLOAD is defined in the base class, so $AUTOLOAD is actually $base::AUTOLOAD, not $sub::AUTOLOAD. Therefore what your function does is install the method in the scope of the base class (and when it is called the next time from a subclass, the method already exists in the inheritance tree).

    pike

      I guess it wasn't clear in my initial example code that I'm creating a new closure for each attribute not just aliasing the same sub.

      $subclass->new_meth will set $AUTOLOAD to "SUBCLASS::new_meth" so will install the closure there. If later I call $other_subclass->new_meth then I'll get another sub in OTHERSUBCLASS::new_meth.

      package A; sub AUTOLOAD { my ($fn) = $AUTOLOAD =~ /^.*::(.+)$/; return if $fn eq 'DESTROY'; *{$AUTOLOAD} = sub { print "$AUTOLOAD $fn"; }; goto &$AUTOLOAD; } package B; @ISA = "A"; package C; @ISA = "A"; package main; $a = bless {}, 'A'; $b = bless {}, 'B'; $c = bless {}, 'C'; $a->shared; # call via baseclass first $b->shared; $c->shared; $b->not_shared; # call via one subclas $c->not_shared; # then another $a->not_shared; # then base class print "\nshared CODE refs:"; print $a->can('shared'); print $b->can('shared'); print $c->can('shared'); print "\nnot_shared CODE refs:"; print $a->can('not_shared'); print $b->can('not_shared'); print $c->can('not_shared');

      Produces output:

       perl -wl eg
      A::shared shared
      A::shared shared
      A::shared shared
      B::not_shared not_shared
      C::not_shared not_shared
      A::not_shared not_shared
      
      shared CODE refs:
      CODE(0x8105cb8)
      CODE(0x8105cb8)
      CODE(0x8105cb8)
      
      not_shared CODE refs:
      CODE(0x8105eb0)
      CODE(0x8105db4)
      CODE(0x8105e50)
      

      So in the second case (which correspond to my usage) you get same closure created and installed in 3 places.

        $subclass->new_meth will set $AUTOLOAD to "SUBCLASS::new_meth" so will install the closure there. If later I call $other_subclass->new_meth then I'll get another sub in OTHERSUBCLASS::new_meth.

        "Doctor, it hurts when I do this" :-)

        Put it in the base class - this should do what you want:

        sub AUTOLOAD { my ($fn) = ($AUTOLOAD =~ /^.*::(.+)$/); return if $fn eq 'DESTROY'; *{$fn} = sub { print "$AUTOLOAD $fn\n"; }; goto &$fn; }
        OK, I have to admit that I checked only part of the story, and it is trickier than I thought. The point is that the full name of the variable is $base::AUTOLOAD, but its contents is "sub::function", not "base::function", as I thought.

        My apologies,

        pike