On Jan 2, 2008 5:14 AM, Dr.Ruud <[EMAIL PROTECTED]> wrote:
> "Chas. Owens" schreef:
> > Adarsh Srivastava:
>
> >> 1. Perl doest seem to catch errors like divide-by-zero error. Eg:
> >> for an input expression like 99 / 0, it simply displays nothing as
> >> output. (no errors thrown).
> >
> > Not true.  If you aren't seeing the errors then you aren't checking $@
> > like I did in my example.
>
> Sorry Chas, for hijacking your reply.
>
> I never understood why checking $@ is done, when checking the eval
> return value itself is available (and it always is, or can be made so).
>
>     eval {
>         ...
>         1;
>     } or do {
>         ...
>     };
>
> The $@ can be set in many ways. Some coders even test $@ with regexes.
> Let's try to get rid of all that, just as with bareword filehandles and
> 2-argument opens.

Um, what sets $@ besides eval?  Take a look at perldoc perlvar:

perldoc perlvar
       $@      The Perl syntax error message from the last eval() operator.
               If $@ is the null string, the last eval() parsed and executed
               correctly (although the operations you invoked may have failed
               in the normal fashion).  (Mnemonic: Where was the syntax error
               "at"?)

If you have code that is setting $@ then you have bad code; Perl can
only protect you from shooting yourself in the foot so much.  However,
it is possible to have more than one eval or even evals you don't know
about in subroutines, but 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:

#!/usr/local/ActivePerl-5.10/bin/perl

use strict;
use warnings;
use feature ':5.10';

sub set_error_at {
        $@ = "foo is bar\n";
}

say "\$@ is [EMAIL PROTECTED]";
set_error_at();
say "\$@ is [EMAIL PROTECTED]";
eval { set_error_at() };
say "\$@ is [EMAIL PROTECTED]";

Of course, you can't trust that $@ will stay the same after that
point, but you also can't trust that $! or $^E will have useful
information except right after an event that you know caused an error.
 That is the nature of global error message variables.

snip
>
> This means that you should rewrite
>
>     my $dbh = eval { ... };
>     if ($@) {
>         ....; # error
>     }
>
> to something like
>
>     my $dbh;
>     eval {
>         $dbh = ...;
>         1;
>     } or do {
>         ...; # error
>     }
>
> (or use an if/else construct of course)
>
> --
> Affijn, Ruud
>
> "Gewoon is een tijger."
snip

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.  The fact
that it makes it easy to check if an error occurred is just a nice
benefit.  What exactly should the code above do if there is an error?
If the database connection timed out we should wait a reasonable (and
random) amount of time and try again.  If the database connection
failed because we have the wrong password there is no point in trying
the faulty password again.  This means you must inspect the contents
of [EMAIL PROTECTED]  If you are already going to do that why not go ahead and 
use
$@ to detect that an error occurred at all?  This saves you from
having to put the constant 1 at the end of your eval (a waste of a
line as far as I am concerned).  In fact, now have the given control
structure, it makes even more sense to use $@:

#warning, untested code and bad regexes
my $dbh;
my $attempts = MAX_DB_CONNECT_ATTEMPTS;
DBI_CONNECT:
until ($dbh = eval { DBI->connect('dbi:foo:dbname=bar', 'user',
'pass', { RaiseError => 1 }) }) {
    given ($@) {
        when (/connection timed out/) { die $@ unless --$attempts;
sleep(3 + int rand 3) }
        when (/password/) { die $@ }
        when (/other thing/) { recover_somehow() }
        default { die "unknown error: [EMAIL PROTECTED]" }
    }
}

* 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.
** Well, to be fair you could use the contents of DBI->errstr, but
that is only in the case of the DBI errors.  Things like a
divide-by-zero exception can only be caught by [EMAIL PROTECTED]

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/


Reply via email to