Limbic~Region has asked for the wisdom of the Perl Monks concerning the following question:

All,
The other night on #perl (freenode), someone asked how to use AUTOLOAD to dynamically wrap all method calls not implemented in their subclass before dispatching to an ancestor class. Since method resolution does not work this way in perl, only clumsy work arounds were provided. It would be straightforward if the list of methods to be wrapped were known but the requestor indicated this wasn't the case.

This got me to thinking about Java and I knew it was time to lay down and rest. For the sake of my sanity, can anyone think of a nice clean way of doing this?

Cheers - L~R

  • Comment on Dynamically wrapping ancestor method calls

Replies are listed 'Best First'.
Re: Dynamically wrapping ancestor method calls
by rafl (Friar) on Dec 11, 2006 at 14:52 UTC

    It was me who asked that question on #perl.

    I could not think of a clean solution to solve that problem using subclassing. Therefor I now use a pattern like this:

    sub new { my $class = shift; my $obj = SomeClass->new( @args ); bless \$obj, $class; } sub AUTOLOAD { ...; $$self->$meth( @_ ); ...; }

    This creates a wrapper class around the class I initially tried to subclass and delegates all method calles to the inside object using AUTOLOAD. This works pretty well so far.

    Cheers, Flo

      You should probably try to figure out what to do with "implicitly defined" methods in your wrapper class, like can() and isa(). My skills don't allow me to either try to suggest something intelligent, or to assure that these two methods are the only ones that you get for free when you create a wrapper like this. Moreover, you should be sure that the already existing methods don't play with caller() (you could try to read Hook::LexWrap to figure out how to deal with this issue).

      Update: from chromatic's answer, I assume that I actually got all the implicitly defined subs :)

      Flavio
      perl -ple'$_=reverse' <<<ti.xittelop@oivalf

      Don't fool yourself.
        sub can { my $self = shift; ${ $self }->can( @_ ) } sub isa { my $self = shift; ${ $self }->isa( @_ ); }
      rafl,
      I intentionally didn't mention you specifically because you didn't post here when I suggested you to. Avoiding subclassing all together was one way I thought of too. I still want to know if anyone has a clean way of doing it as originally asked. Sometimes innovative thinking comes from unexpected places.

      Minor wording updates

      Cheers - L~R

Re: Dynamically wrapping ancestor method calls
by jbert (Priest) on Dec 11, 2006 at 17:13 UTC
    Couldn't you walk the superclasses' symbol table to build a list of methods that need wrapping (and then install corresponding methods in the subclass?). Perhaps at first subclass 'new' time, to capture any init-time dynamic methods in the superclass?

    You'd lose out if anyone did anything as gross as installing methods in the superclass at methods at runtime, but who would abuse perl like that ;-) <-- Note ironic smiley.

      jbert,
      You could and that is one of the ideas put forward. Do you know how it would work if you had more than one ancestor before you got to UNIVERSAL? I don't know of all the issues but it seems like there would be more than just what would happen if the symbol table was modified at runtime.

      I am not sure there is a good answer, that's why I asked. To state it a different way, how can I overide perl's method resolution process and insert my own.

      Cheers - L~R

        If you assume that the symbol tables of your superclass tree aren't going to change, you could scan them in the same order that perl does (recursively take @ISA from each one and walk up the hierarchy), and thus build up a complete list of possible methods on the subclass.

        Since that ordering is documented, you aren't really abusing internals knoweldge to do that.

        It seems to me that that should work. It still isn't very nice though. I still like the proxy object, actually. That seems to work pretty well.

        Out of interest, may I ask about the the original problem which is being addressed by the automagic wrappering?