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

I have a situation where I'm overriding some methods in a class and it's breaking the effects of Carp. The parent class will croak, but the error message then lists the line number of child class that called SUPER rather than the real client code.
$foo->SUPER::bar(@_); # <-- errors give this line number
There must be a way around this using some of the stuff that stacktraces are done with in Carp, right? Anyone have something handy?

UPDATE: All good suggestions. As it turns out, my first idea (using goto) actually worked, but I couldn't tell. The real problem was a different class turning off $dbh->{RaiseError} so that these were really warnings rather than exceptions, and thus not being caught by things that should have caught them. Sigh.

Replies are listed 'Best First'.
Re: manipulating call stack
by Joost (Canon) on Nov 07, 2007 at 00:05 UTC
    Well.. carp does unintuitive things like that because it's more or less the only way to do it without further information. I can think of two solutions:

    1. Try goto &SuperClass::bar; instead - but make sure @_ includes the object/class reference as the first argument. See goto

    2. Do eval { $self->SUPER::foo(@_) }; carp $@ if $@

    update: it occurs to me that whole idea of carp & croak is wrong and that the only really useful thing to do is to print a complete stack trace (like confess does) - i.e. use Carp 'verbose' in your module.

      I actually tried goto first, since it sounded like the right tool for the job, but couldn't get it to work at all. It gave me bizarre errors that I couldn't track down.

      I tried the eval already too, but of course it just gives the same message. I think I could maybe get it to work if I did careful editing of $@, since I think croak is looking at it and seeing a line number already there and that's why it fails.

      The parent class is a CPAN module while I'd prefer not to mess with, except as a last resort.

      I'll try the eval or goto again. Maybe I can get it to work if I persevere. Thanks for the suggestions.

Re: manipulating call stack
by tilly (Archbishop) on Nov 07, 2007 at 02:35 UTC
    In your package, make @CARP_NOT include all of the packages that you're overriding methods in. Alternately make @CARP_NOT in the package you overrode methods in be its existing @CARP_NOT or existing @ISA plus your package name.

    There are subtle differences between the two, but either should help for most simple cases. (Suppose that A is a subclass of B is a subclass of C and you've overridden foo in B. The first won't succeed if your foo is called from A and the second won't succeed if your foo is called from C.)

    If those, or a combination of those, don't solve your problem, then you have 2 possible solutions. The first is to load Carp::Heavy, then override Carp::trusts with a function of your own choosing that does whatever you want. (Carp should really have a hook for that purpose, but I didn't think of it when I should have, and at this point I'm not motivated to design and implement one. If you want to do so, be my guest.) The second is to override the methods with an eval so your new functions have the right package.

Re: manipulating call stack
by xdg (Monsignor) on Nov 07, 2007 at 05:26 UTC
    There must be a way around this using some of the stuff that stacktraces are done with in Carp, right?
    local $Carp::CarpLevel = $Carp::CarpLevel + 1;

    Hacky, but I think I've used this in the past and got it to work.

    The other thing you could mess with is Sub::Uplevel and uplevel() your parent call -- but I'd be a little nervous about that (maybe because I know the guts of Sub::Uplevel). Unless you're doing any sort of protected class stuff that uses the call stack, this is another hack that might work.

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.