![]() |
|
Your skill will accomplish what the force of many cannot |
|
PerlMonks |
comment on |
( #3333=superdoc: print w/replies, xml ) | Need Help?? |
I'd call both cases a bug. local's restore needs to be done before die sets $@. Yes, I understand that this makes the implementation slightly more difficult since it requires storing what will end up in $@ somewhere while the stack is unwound. But it also allows for fixing the long-standing bug of DESTROY methods being able to clobber $@. Given what I perceive as the perversity of p5p's decision making, I'll note that at the very least BEGIN handling needs to be fixed to check the return value of eval rather than checking $@. Yes, this might mean forcing something like "; 1" onto the end of the BEGIN block's code before it is string-eval'd. But a better fix is discussed below. To reduce the impact of the change, I'd still set $@ early but also have eval save that value and set $@ to it right before it returns. (Update: Actually, eval isn't in the picture until the stack unwinding runs into it, so die needs to save $@ somewhere for eval to copy back into $@. And the stack unwinding can involve other cases of eval and die so we really need a stack of these saved values. So die should set $@ then push @@, $@;. Just before eval returns, it should $@= pop @@;?) (Update2: Perhaps better to have eval push a blank value onto @@ up front and have die set both $@ and $@[-1] then $@= pop @@; when eval finishes will always be safe. @@ would start out with one entry in it that perl itself would use so that DESTROY/local can't clobber the error message that caused perl to die. This means that you can use 'die' inside of DESTROY or such to change the error message but you can't just change $@ to do that.) I didn't mind the DESTROY bug in eval so much because local($@); fixes it. But this bug really sucks (in that I can't see a reasonable way to work around it -- forcing BEGIN { my $pe= $@; ...; $@= $pe } isn't reasonable, IMHO). This appears to mean that it is best to use local $@; to prevent $@ from being clobbered in some conditions, but also that any local $@; in a scope that gets unwound will break a surrounding eval. So the fix for one aspect of the bug makes the other aspect of the bug more likely. Time to just fix it. Looking into this also provided the following surprise:
prints "()" when I thought it should print "(Before)". I expect $@ to be set to the empty string when the eval returns successfully. But it appears that instead, $@ is set to the empty string when eval starts. Further testing shows that it is also set to the empty string at the end so I don't see the value in setting it at the start so I'd consider that a low-priority bug. Here is a little test script:
And my results:
- tye In reply to Re^3: Unexpected result after localizing eval_error variable "$@" within "BEGIN" block (bugs)
by tye
|
|