On Jan 2, 2008 8:11 PM, Dr.Ruud <[EMAIL PROTECTED]> wrote: > Chas. Owens schreef: snip > > If you have code that is setting $@ then you have bad code; > > eval sets [EMAIL PROTECTED] Not all code that uses eval, is bad code. > ;-) snip
When I said "is setting $@" I meant other than by the eval mechanism. $@ must be set by something, otherwise it would be useless. snip > I don't think this is inside your box either: > http://www.google.com/codesearch?q=%22local+%24%40%22&hl=en&btnG=Search+Code > finds plenty of popular modules that set (a localized) $@, to protect > the outer [EMAIL PROTECTED] snip Those aren't setting $@, they are localizing it, which is the right thing to do. snip > > if your if (or given, see below) is right > > next to an eval, then there is no way* for it to be set other than by > > that eval: > > Yes, there is: evals can happen to run "intertwined". snip Only if you have made a grave mistake (see below) and even then localizing $@ protects its value. > > > The $@ variable is not just used for checking to see if an error > > occurred; that isn't even its primary purpose. Its reason for > > existing is that it holds the error that actually occurred. > > Nothing in the "eval{...;1} or do{...};" construct prevents you from > inspecting $@ inside the do{}. So it beats me why you even mention the > possibility, $@ holds important information (like a string, or a > reference to error information); not using that would be very stupid. > > > > If you are already going to [test [EMAIL PROTECTED] why not go ahead and use > > $@ to detect that an error occurred at all? > > Because testing $@ is simply less accurate than testing the return value > of eval. Why choose the next best thing, if the best is also there? snip It contains vital information. If you are in the habit of destroying that vital information through bad practices, then yes you should use the return value of eval to determine success/failure. Personally, I prefer not to destroy vital information. Neither of us will be happy until we get Perl 6's try/catch syntax (maybe they will backport it to Perl 5.12). snip > > * Well, theoretically a signal handler could be called in the brief > > span of time between the eval and the if and $@ could be set, but not > > only is highly unlikely, it is also bad practice to be calling an eval > > (or doing anything non-trival for that matter) in a signal handler. > > In production code such "coincidences" happen. > > Check `perldoc -f alarm` which mentions "unexpected errors" and that the > "\n" is required. snip Yes, but it only if you use an eval in a signal handler, which is a bad idea for many reasons, and fail to protect $@ by localizing. Signal handlers need to execute the smallest amount of code possible, the best case being just an assignment to a variable that the main body of the program should check. The fact that $@ is cleared by signals is a bug introduced in the 5.8 line and should be fixed. The fact this it took this long for people to notice the bug points to the very rare set of circumstance required for it to have an effect*. The list of times $@ can be monkeyed with in that thread are all the result of improper, buggy uses of $@ and eval**. If we were to take that attitude we should also never use $_, $/, or any other global variable since they all have the same spooky-action-at-a-distance issue when missued: #!/usr/bin/perl use strict; use warnings; $SIG{ALRM} = sub { $_ = "broken\n"; die }; $_ = "works\n"; eval { alarm 1; 1 while 1; }; print; Saying that $@ is untrustworthy and should not be used is like cutting off your foot to keep from shooting it. The answer is to not shoot your foot: #!/usr/bin/perl use strict; use warnings; $SIG{ALRM} = sub { local $_ = "broken\n"; die }; $_ = "works\n"; eval { alarm 1; 1 while 1; }; print; Anytime you use eval in a signal handler (a bad idea to start with) you need to localize [EMAIL PROTECTED] If you use an eval in a DESTROY method, you need to localize [EMAIL PROTECTED] This is why we have local(). I am all for avoiding tricky situations were there is nothing to be gained, but the only way to know what happened in an eval is to examine $@; if we can't trust it then we can't act in a sensible manner. Module level error functions and variables cannot detect Perl runtime exceptions like divide-by-zero: my $max = 0; . . . if (eval { $sth->execute(3/$max) }) { die "insert failed with " . $sth->errstr; } This code snippet would die with the string "insert failed with " or worse yet "insert failed with <some unrelated error>" because $DBI::err was never reset (since execute is never actually called). The only sane thing here is to use $@ and since it is the only sane thing to do, you should protect the value of $@ and fix any bugs that might interfere with it (and anything that interferes with the value between a call to eval and the if/given that follows it is a bug). Of course, the error message could be a little better: if (eval { $sth->execute(3/$max) }) { die "insert failed for the value 3/$max with: " . $sth->errstr; } which would give you a fighting chance of seeing that the error is a divide-by-zero error, but still not as good as if (eval { $sth->execute(3/$max) }) { die "insert failed for the value 3/$max with: $@"; } * you must be using signal handling and the signal must occur in the very short time between the eval and the use of $@ ** my favorite was "The value $@ in could be an overloaded object. If coded poorly, examining the value clobbers [EMAIL PROTECTED] In fact, at work $@ usually is a stringification overloaded object. An earlier iteration computed "$@" improperly and would clobber $@ during the compute. " Wow, just wow. The nerve of this person. He/She is saying that his/her company extended the Perl langauge, and poorly at that, and therefore everyone else in the world shouldn't use a well documented variable the way it was intended to be used. Amazing. The others have similar issues: "$@ can be false after error because an eval{} happened during a ->DESTROY. $@ can be true after *NO* error because an a die happened during a ->DESTROY. The eval will still succeed though." In both these cases the bug is in the DESTROY method (failure to localize $@), not in the use of [EMAIL PROTECTED] "$@ could be tied and act arbitrarily. " This is just silly. If $@ is tied then the person tie'ing it better make sure it acts the way $@ is designed to act or it is bug in his or her code, not in the normal use of [EMAIL PROTECTED] See the his/her overweening hubris (with a little h) above. -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/