sub foo {
local $@;
eval { # a generic wrapper, doesn'tknow about bar()'s details
bar();
};
if ( $@ ) {
# do something meaningful
die $@;
}
}
sub bar {
die "blah";
}
eval { foo() };
warn "Error: $@";
in the 'foo' subroutine $@ is localized to prevent clobbering it in
cases such as:
eval { ... };
foo();
if ( $@ ) { # for the prev eval }
From a control flow POV everything works correctly here, but in the
outermost eval { } the value of $@ is not preserved (it will jump
though). The value is just ''.
Since there is no other way to know if the eval actually failed
without inspecting $@ that makes it faily useless, and furthermore
the documentation of eval implies this should not be the case (but
doesn't mention local).
I believe this is an implementation detail, likely die() in the
context of an eval assigning to $@ with it's localization stack,
instead of the assignment happenning in the scope of the eval { }
that is actually trapping the error, so in effect the error that it
trapped is in $@.
The work around is in foo():
sub foo {
my $e;
{
local $@;
eval { bar () };
$e = $@;
}
if ( $e ) { die $e }
}
but that kinda sucks.
Every time this happenned to me it took a really long while to
figure out, a conservative guess is that I've lost about 2-3 days of
my life to this behavior over the past few years. This is because
it's action at a distance on several levels.
--
Yuval Kogman <nothingmuch@woobling.org>
http://nothingmuch.woobling.org 0xEBD27418
Thread Next