in reply to Solving the SUPER problem in Mixins with a Dispatch Method

At the risk of breaking ranks here, I will attempt to help actually answer your question, rather than lecture you about OO and the evils of MI (which no doubt you have already heard, and dont agree with (<sarcasm>persish the thought that one could disagree with the great OO idealouges</sarcasm>)).

Does anyone know how to reliably extract the name of the calling method, so that I can ommit that from the calls to the NEXT method? The ( caller(0) )3 can be hidden inside evals and such; do I just walk back through stack frames until I find one that's not an eval?

The docs for caller talk about how you could do this.

With caller(EXPR), it returns some extra information that the debugger uses to print a stack trace. The value of EXPR indicates how many call frames to go back before the current one.
($package, $filename, $line, $subroutine, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask) = caller($i);
Here $subroutine may be (eval) if the frame is not a subroutine call, but an eval. In such a case additional elements $evaltext and $is_require are set: $is_require is true if the frame is created by a require or use statement, $evaltext contains the text of the eval EXPR statement. In particular, for an eval BLOCK statement, $filename is (eval), but $evaltext is undefined. (Note also that each use statement creates a require frame inside an eval EXPR frame.) $subroutine may also be (unknown) if this particular subroutine happens to have been deleted from the symbol table.
You will likely need to test a number of values to handle both the eval BLOCK and the eval EXPR and not have it get confused.

While I understand your hesitancy with AUTOLOAD, it would remove this entire problem. Also if you use the technique I showed in my post to your previous thread, in which you create a SUPER:: sub-package (which can easily be defined inline in your Base class), then you need not worry about having AUTOLOAD in any of you "real" classes.

-stvn

Replies are listed 'Best First'.
Re^2: Solving the SUPER problem in Mixins with a Dispatch Method
by simonm (Vicar) on Oct 14, 2004 at 17:32 UTC
    At the risk of breaking ranks here, I will attempt to help actually answer your question ...

    *grin*

    Does anyone know how to reliably extract the name of the calling method, so that I can ommit that from the calls to the NEXT method?
    While I understand your hesitancy with AUTOLOAD, it would remove this entire problem.

    Perhaps we're not talking about the same "problem."

    The built-in syntax for an empty wrapper is:

    sub compile { (shift)->SUPER::compile(@_) }

    The syntax I'm currently using is:

    sub compile { (shift)->NEXT('compile', @_) }

    What I'm hoping for is to omit the method name and have it picked up from context:

    sub compile { (shift)->NEXT(@_) }

    All of the AUTOLOADed solutions seem like they'll still require the current method name to be specified:

    sub compile { (shift)->SUPER::DISPATCH::compile(@_) }

    Admittedly, it's a minor point, but if you're going to have a rule that says that you can't redispatch to a different method name, it seems gauche to make the caller write out the method name again.

      Perhaps we're not talking about the same "problem."

      You are right, we were not. Sorry, only had one cup of coffee when I wrote that (hence the sarcasm and bitterness). However, I have now had more than one cup of coffee and I think this might help you.

      #!/usr/bin/perl use strict; use warnings; { package MyObject::Base; sub NEXT { my ($self, @args) = @_; my ($package, $filename, $subroutine); my $i = 1; ($package, $filename, undef, $subroutine) = caller($i); while ($subroutine eq '(eval)' || $filename eq '(eval)') { ($package, $filename, undef, $subroutine) = caller(++$i); } print "NEXT was called from : $subroutine\n"; } package MyObject; our @ISA = ('MyObject::Base'); sub compile1 { (shift)->NEXT(@_) } sub compile2 { eval { (shift)->NEXT(@_) } } sub compile3 { eval { eval { (shift)->NEXT(@_) } } } sub compile4 { my $self = shift; eval '$self->NEXT(@_)' } sub compile5 { my $self = shift; eval 'eval "$self->NEXT(\@_)"' } + sub compile6 { my $self = shift; eval { eval { eval { eval 'eval { eval "\$self->NEXT(\@_)" }' } } } } } MyObject->compile1(); MyObject->compile2(); MyObject->compile3(); MyObject->compile4(); MyObject->compile5(); MyObject->compile6(); __OUTPUT__ NEXT was called from : MyObject::compile1 NEXT was called from : MyObject::compile2 NEXT was called from : MyObject::compile3 NEXT was called from : MyObject::compile4 NEXT was called from : MyObject::compile5 NEXT was called from : MyObject::compile6

      -stvn