Why do I need to localize $@ before using eval?
Asked Answered
L

3

6

I'm aware of the fact that $@ is a global variable, still I can't figure out why I need to localize it before using eval:

For instance:

eval { SOME_FUNC_THAT_MAY_DIE(); };
if ($@) {
  print "An error occured!\n";
}

The only possible thing I can think of is, if some signal handler will call die at the same time I try to read $@, what am I missing here?

Lucio answered 4/7, 2012 at 19:30 Comment(0)
C
12

The reason to say local $@ before calling eval is to avoid stepping on your caller's $@. It's rude for a subroutine to alter any global variables (unless that's one of the stated purposes of the subroutine). This isn't really an issue with top-level code (not inside any subroutine).

Also, on older Perl's, any eval called during object destruction would clobber the global $@ (if the object was being destroyed because an exception was being thrown from an eval block) unless $@ was localized first. This was fixed in 5.14.0, but many people are still running older Perls.

Choking answered 4/7, 2012 at 19:50 Comment(0)
D
9

The Try::Tiny module documentation gives the rationale (as well as providing an alternative):

When you run an eval block and it succeeds, $@ will be cleared, potentially clobbering an error that is currently being caught. This causes action at a distance, clearing previous errors your caller may have not yet handled. $@ must be properly localized before invoking eval in order to avoid this issue. More specifically, $@ is clobbered at the beginning of the eval, which also makes it impossible to capture the previous error before you die (for instance when making exception objects with error stacks).
Devland answered 4/7, 2012 at 19:47 Comment(1)
The reason I found this post, was exactly because I didn't understand exactly this paragraph in Try::Tiny's documentation. What does potentially clobbering an error that is currently being caught mean? ;-)Nominee
F
0

You don't need to, but if you wrote code like this, localizing $@ would keep the first error as it was. and if you didn't write code like this, the local $@ would have no effect. better would be to handle errors before running any extra code.

eval {
    die "error 1\n";
};
foo();
print "processing $@\n";

sub foo {
    #local $@;
    eval {
        die "error 2\n";
    };
}
Finality answered 28/1, 2020 at 21:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.