John M. Dlugosz has asked for the wisdom of the Perl Monks concerning the following question:

In 2002/2003 I wrote Exporter-VA, or Exporter with Versioning and Aliasing, with the intention of then updating classic modules to be more OO, allowing the old and new API to co-exist in one release.

I never got around to doing any of that.

But, Exporter::VA doesn't work on newer versions of Perl. I get an error, “(Can't goto subroutine from an eval-block at /var/content/dev/Exporter-VA-1.3.0.1/blib/lib/Exporter/VA.pm line 558.”

The code in question is:

sub autoload_symbol { my ($self, $symbol, @extra)= @_; my %memory; my $home= $self->{'..home'}; my $thunk= sub { my $retval= eval { my $caller= _calling_client(); # so I don't have to figure it +out multiple times my $f= $memory{$caller}; unless (defined $f) { $f= $memory{$caller}= $self->resolve ($caller, $home->VERSIO +N(undef,$caller), '&'.$symbol, [@extra]); } goto &$f; ######### Error line is Here <<<<<<<<< }; if ($@) { carp "(Exporter::VA) Cannot redirect to versioned function ($@) +"; } return $retval; }; no strict 'refs'; *{"${home}::$symbol"}= $thunk; }
The AUTOLOAD calls this to create and install the thunk for the named function, which checks the caller and redirects to the old version or the new version as the caller declared it wanted. This allows functions to change in incompatible ways while still supporting old code in the same programs.

The generated thunk jumps to the actual target using the redirection form of goto. I guess it's complaining that I'm catching exceptions from that process and, at the very least, giving a more meaningful error message, and Carps rather than just plain dieing.

If I change the eval to a do (and remove the following if "catch" statement) it passes all tests. So how do you trap errors now? Having stuff that is not allowed in a try block just isn't nice.

Replies are listed 'Best First'.
Re: My AUTOLOAD doesn't work in newer Perls. How to fix?
by JavaFan (Canon) on May 17, 2011 at 09:38 UTC
    goto &$name effectively removes the calling block from the call stack. With the eval block gone, how would you trap errors (it won't even return anything)? Pick one: have the eval block in the call stack (and then use &$f;), or don't try to trap errors.
      I see what you mean. I don't expect it to trap an error in the dispatched function. I worry about an error in the goto itself, not finding the target or "going" there.

      Can that happen? I guess if $f is indeed not still undef and is a code ref, that should be good enough?

      Thanks.

        If you can live with just using &$f instead of goto &$f, then use that. (Just realize that &$f returns, while goto &$f doesn't - at least not to the place it was called from).

        If $f is a code ref, you're good. Otherwise, $f is a symbol, and you can provide messages for !exists(&$f) and !defined(&$f).

Re: My AUTOLOAD doesn't work in newer Perls. How to fix?
by jettero (Monsignor) on May 17, 2011 at 09:36 UTC
    It says you can't goto from an eval block. Seems the AUTOLOAD is working, but you'll need a different control flow since you can't goto from an eval.
      That's what I said.

      How do I trap errors produced by a construct that is not allowed in an eval block?

        You call the routine normally, instead of using goto.

        Think a bit about it: the goto SUBREF thing replaces the current call frame. How could it still keep the exception handler of old call frame?