Re: Catching a 'division by zero' error with Exception::Class
by dreadpiratepeter (Priest) on Sep 15, 2008 at 14:36 UTC
|
That won't work. the system dies with a division by 0 error when the 23/0 happens. The or clause that throws your error never occurs.
You would have to either, throw the exception outside of the eval, or override the default die bahavior to throw the exception instead. Off the top of my head, I am not familiar enough with the exception classes to answer, but I'm sure there are other monks that will.
UPDATE: Actually now that I think about it, your confusion occurs because Exception::Class is more for trapping application errors than for trapping underlying system errors. A better example for testing would be: open my $FH ">unwritable_file" or MyException->throw( error => 'I feel
+ funny.' );
-pete
"Worry is like a rocking chair. It gives you something to do, but it doesn't get you anywhere."
| [reply] [d/l] |
|
|
pete,
thanks for your answer, but I think your example 'suffers' from the same problem: The exception cannot be catched!
Output:
Died at foo.pl at line 27.
That means, not the specific error is thrown but the last else clause:
else
{
$e = Exception::Class->caught();
ref $e ? $e->rethrow : die $e;
}
Or am I wrong?
ben
| [reply] [d/l] [select] |
|
|
| [reply] |
|
|
|
|
|
|
|
The division by zero will raised it's own exception. So what you can do is either catching the exception using the Exception::Class:Base :
#!/usr/bin/env perl
use Exception::Class;
# try
eval {
(my $result = (23/0));
};
# catch
if ( my $e = Exception::Class->caught() )
{
# You can rethrow the exception with your own like MyException her
+e
die "ERROR: division by zero\n$e\n"
}
or test the value before doing the division manually:
#!/usr/bin/env perl
use strict;
use Exception::Class
( 'MyException' );
my $number1 = 12;
my $number2 = 0;
my $result;
# try
eval {
if ($number2 == 0) {
MyException->throw( error => 'I feel funny.' );
}
$result = $number1 / $number2;
};
# catch
if ( my $e = Exception::Class->caught('MyException') )
{
warn $e->error, "\n", $e->trace->as_string, "\n";
warn join ' ', $e->euid,
$e->egid, $e->uid, $e->gid, $e->pid, $e->time;
exit;
}
else
{
$e = Exception::Class->caught();
ref $e ? $e->rethrow : die $e;
}
Hope this help.
DISCLAIMER: I still learning perl also. Anybody please correct me if I am wrong. Thanks | [reply] [d/l] [select] |
Re: Catching a 'division by zero' error with Exception::Class
by moritz (Cardinal) on Sep 15, 2008 at 14:40 UTC
|
Your program dies before it gets to the line with MyException->throw, because the division by zero happens before.
One way to catch that kind of error is by assigning a handler to $SIG{__DIE__}. But maybe Exception::Class even has a mechanism for automatically wrapping such errors. | [reply] [d/l] [select] |
|
|
The compiler is catching the division by zero before your code has any opportunity to tackle it. I made the following work:
#!/usr/bin/env perl
use Exception::Class ( 'MyException' );
# try
my $z = 0;
eval {
eval { my $result = ( 23 / $z ) }
|| MyException->throw( error => 'I feel funny.' )
};
# my $e;
# catch
if( my $e = Exception::Class->caught( 'MyException' ) ) {
warn $e->error, "\n", $e->trace->as_string, "\n";
warn join ' ', $e->euid, $e->egid, $e->uid, $e->gid, $e->pid, $e->ti
+me;
exit;
} else {
$e = Exception::Class->caught();
ref $e ? $e->rethrow : die $e;
}
__END__
I feel funny.
Trace begun at index.pl line 9
eval {...} at index.pl line 8
1000 1000 1000 121 120 117 115 109 108 106 104 46 44 30 29 25 24 20 6
+4 0 1000 1000 1000 121 120 117 115 109 108 106 104 46 44 30 29 25 24
+20 6 4 0 10107 1221493762 at index.pl line 17.
[]s, HTH, Massa (κς,πμ,πλ)
| [reply] [d/l] |
|
|
dear massa, thanks for your help. Would you mind to give a quick explanation of the effect of this eval wrapper around the division by zero expression?
| [reply] |
|
|
Re: Catching a 'division by zero' error with Exception::Class
by betterworld (Curate) on Sep 15, 2008 at 15:40 UTC
|
The exception even happens before the eval block is entered. This is because perl calculates immediate expressions during compile time. This should demonstrate it:
$ perl -lwe 'eval{0/0}'
Illegal division by zero at -e line 1.
To work around that, you can try putting 0 into a variable. | [reply] [d/l] |
|
|
$ perl5.10.0 -ce '1/0'
-e syntax OK
$ perl5.8.8 -ce '1/0'
Illegal division by zero at -e line 1.
(I think it was intentionally removed in newer perls because it could break code even if it's not reachable; consider this example:
my $DEBUG = 0;
...
if ($DEBUG) {
$verbosity = 10 / $DEBUG;
}
in which case constant folding might break things).
(Update: in that last example there is no constant folding at all, because variables are not constant folded. ikegami suggested to use constant DEBUG => 0; instead, which should better demonstrate what I was thinking about). | [reply] [d/l] [select] |
Re: Catching a 'division by zero' error with Exception::Class
by pileofrogs (Priest) on Sep 15, 2008 at 21:23 UTC
|
Before going into Exception classes, you might want to play with eval without the Exception classes. Get familliar with how perl handles exceptions before doing anything else.
EG
eval { die "woot!\n" };
if ( $@ =~ /woot/ ) {
die "This is a 'woot' error!\n"
}
else {
die $@;
}
If you're not familiar, eval {} and eval "" are totally different animals, so watch out for that confusion. eval {} is really like a try block in most other languages. eval "" is like eval in other languages.
| [reply] [d/l] |
|
|
I completely agree, eval-die is flexible enough for most use. Is there any advantage with hierarchical exceptions which is worth the addition code and modules?
The original problem can be written as:
use warnings;
use strict;
use 5.0100;
eval {
print 10/0; # equivalent to: die "Illegal division by zero";
};
if($@) {
if($@ =~ /Illegal division by zero/) {
print "I feel funny\n";
exit;
} else {
die $@;
}
}
# No exception thrown.
print "What do you know, Perl can divide by zero.\n";
Updated: this code doesn't work properly before Perl 5.10, so I added a 'use' statement to stop it. | [reply] [d/l] |
|
|
| [reply] |
|
|
|
|