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

2019-06-20 07:51发布

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?

2条回答
迷人小祖宗
2楼-- · 2019-06-20 07:57

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.

查看更多
Lonely孤独者°
3楼-- · 2019-06-20 08:07

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).
查看更多
登录 后发表回答