in reply to Re3: Calling SUPER in MethodMaker-generated methods
in thread Calling SUPER in MethodMaker-generated methods

Actually, the eval is trapping the error. When I put a die $@ if $@; after the eval, it propagates the same error.

Duh, you're right. :-) I was testing for @$ instead of $@. /me slaps forehead.

The reason it works without Class::MethodMaker is (near as I can tell, anyway) that you're creating the sub in the same class for which you want to find the super class. In other words, it might be that if you wrote a third class that installs the method (in which SUPER is called) into the base class, it wouldn't work.

I think you're right. Could it possibly be that I've discovered a feature that is impossible for Perl? Nahh... probably I just haven't found the answer yet. :-)

Creating a simple test module that installs the SUPER-calling method into the example which doesn't use Class::MethodMaker would tell you if the issue is actually with using SUPER outside the base class, though, so that's maybe a good avenue to explore.

I'll give that a shot (not sure if I can do it, but I'll try).

-Dan

  • Comment on Re: Re3: Calling SUPER in MethodMaker-generated methods

Replies are listed 'Best First'.
Re5: Calling SUPER in MethodMaker-generated methods
by bbfu (Curate) on Jul 09, 2003 at 04:02 UTC

    Ok, I think I found the cause of the problem, and a way to work around it, though it's a little ugly.

    If you look in perlboot under SUPER, you find the following:

    So, "SUPER::speak" means look in the current package's @ISA for "speak", invoking the first one found.

    In other words, SUPER ignores the class of the object it's called upon, and always looks in the current package's @ISA to find the super class. So, when you create the anonymous sub to be the method, it's actually created in your CustomMethodMaker class, and so that's whose @ISA it uses, even though it's later installed into the FixedBug class. (Technically, it's not actually put into the FixedBug class. Rather, a reference to it is put into FixedBug's symbol table. The sub still resides in CustomMethodMaker.) Personally, I don't think is the correct thing to do (I think SUPER should look in the @ISA of the package that the object is blessed into) but it's documented, so it can't be a bug. ;)

    So, to do what you want to do, you need to force the call to SUPER to be in the correct package. The way to do this is to note what package your installer function is called from, and manually set yourself back to that package just prior to calling the super-method. Of course, since you only know what package your installer function is called from at run-time, you have to set the package dynamically at run-time, via (string) eval.

    I created a simple set of test classes. You should just need to use the eval and caller() lines in MyTest::MethodInstaller::install(). With your original example code, you'll have to get the caller two levels higher (ie, caller(2)). Once for the import, and once for something else internal to Class::MethodMaker. Or, you could use Class::MethodMaker's internal (undocumented) find_target_class() method, which searches up the call stack for the first namespace which is not a descendant of Class::MethodMaker. That would probably be better (more robust, somewhat less likely to change).

    The code:

    Well, that should get you working, though I think the eval trick is ugly and shouldn't be necessary in the first place. Oh well. C'est la vie.

    bbfu
    Black flowers blossom
    Fearless on my breath

      Done! For the record, I attached the final MethodMaker-derived code. Would you accept a small tip via PayPal (if so, what e-mail should I use)?

      I'm going to see about submitting this for the MethodMaker maintainer.

      #################################################################### ## CustomMethodMaker #################################################################### package CustomMethodMaker; use base ( 'Class::MethodMaker' ); use Carp; =head2 grouped_fields_inherit Works like grouped_fields, except that it also calls the parent class. =cut sub grouped_fields_inherit { my ($class, %args) = @_; my %methods; foreach (keys %args) { my @slots = @{$args{$_}}; $class->get_set(@slots); my $method_name = $_; my $caller = $class->find_target_class(); $methods{$_} = sub { my ( $self ) = @_; my @parent_slots = (); my $to_execute = "SUPER::$method_name"; # # Without $caller and eval, the following line causes this err +or: # # Can't locate auto/CustomMethodMaker/SUPER/[METHOD].al in @ +INC # @parent_slots = eval "package $caller; return \$self->SUPER::$ +method_name(\@_); 1" or die $@; return ( @parent_slots, @slots ); }; } $class->install_methods(%methods); } 1;
      -Dan

        Would you accept a small tip via PayPal

        Nah, don't sweat it. I enjoyed helping. :) I appreciate the offer, tho.

        Update: Re: your code; I just wanted to point out that you should probably either put the assignment to @parent_slots inside the eval, since it's conceivable that the super-method could correctly return an empty list which would cause your code to die, or make the test for dying an explicit check on $@ (in which case the 1; at the end of the eval is superfluous). IOW, it's best to do this:

        @parent_slots = eval "package $class; \$self->SUPER::$method_name()"; die $@ if $@;

        Also, if you're going to pass @_ in to the super-method, you need to shift $self off first, instead of setting it via list-context assignment. (Otherwise, the super-method gets two copies of $self.)

        bbfu
        Black flowers blossom
        Fearless on my breath

      Woo hoo! Thanks, bbfu. I'll have to try this out in the morning. (FYI, don't do eval "package $self";, it causes a Segmentation Fault.)

      -Dan

Re: Re: Re3: Calling SUPER in MethodMaker-generated methods
by danb (Friar) on Jul 08, 2003 at 23:03 UTC
    Creating a simple test module that installs the SUPER-calling method into the example which doesn't use Class::MethodMaker would tell you if the issue is actually with using SUPER outside the base class, though, so that's maybe a good avenue to explore.

    I'll give that a shot (not sure if I can do it, but I'll try).

    :-( I tried, but I can't figure it out. Here's hoping that we'll figure it out eventually.

    -Dan