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/


Reply via email to