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

Hi,

I've recently found a bit of code that would be a good candidate to make use of the goto &sub form of the goto command (the one that AUTOLOAD uses), with the minor problem being that it is one level down the stack from what I want to replace.

For example:

sub do_something { my $param = shift; my $info = get_info($param); # more things happen do_something_else($param, $info); } sub get_info { my $param = shift; my $info; if($param eq 'option 1') { $info = 'blah'; } elsif($param eq 'option 2') { do_something_that_might_fail($param) #POINT A $info = 'foo'; } else { $info = 'bar'' } return $info; }

do_something() is called at some point, and then it descends into get_info(). If $param is 'option 2' then a function is called which might fail (at POINT A) - if this fails I'd like to replace the currently running do_something('option 2') with do_something('option 1').

I can replace get_info('option 2') with get_info('option 1') (by setting @_ appropriately and then calling goto &get_info; after POINT A), which will return the $info that I want it to, but when do_something then calls do_something_else it will still be using its original version of $param - 'option 2'.

Is there some way of replacing the caller of the currently running frame of reference with some other function in a similar way to how goto &sub replaces the current running function (without diving too far into the magic internals of perl)?

I'm well aware that for the current problem I'm working on it would be an easy solution, but not necessarily a good one - the current situation may be fixed easily, but if get_info is ever called by any other function things get Sub-Optimal quickly - I just had my curiousity piqued by the potential that may exist.

Thanks for reading,

Prowler
 - Spelling is a demanding task that requies you full attention.

Replies are listed 'Best First'.
Re: goto &sub up the stack
by gaal (Parson) on Feb 18, 2005 at 08:34 UTC
    The unmagical solution would be to wrap the part of get_info after my $param = shift with a named scope, then when do_something_that_might_fail does fail, change $param and redo the loop.

    If you insist on goto &sub, use the fact that assigning to @_ in its entirety makes it shed its aliasing.

    if ($failed) { @_ = "option1"; # and NOT $_[0] = "option1"; goto &do_something; }
    (Untested.)
Re: goto &sub up the stack
by Thelonious (Scribe) on Feb 18, 2005 at 12:04 UTC
    The easiest thing to do is to have &get_info return undef on failure. Then you can check to see if you have good $info back, in &do_something. If not, then recall &get_info with another arg to see if that works. You don't really need to get too complicated with this.

    sub do_something { my $param = shift; # just add a test for success here: my $info = get_info($param) || get_info('option 1'); # more things happen do_something_else($param, $info); } sub get_info { my $param = shift; my $info; if($param eq 'option 1') { $info = 'blah'; } elsif($param eq 'option 2') { return unless # <-- test whether a failure occurred; return undef do_something_that_might_fail($param) #POINT A $info = 'foo'; } else { $info = 'bar'' } return $info; }
    I hope that's clear.

    I'm not sure HOW the failure occurs. Maybe by dying, maybe by returning false from &do_something_that_might_fail ... I chose the latter for this example. Please put in a test that works for you.