baurel has asked for the wisdom of the Perl Monks concerning the following question:

hi
I'd like to learn to program good perl ... I think one element to achieve that is to provide hirarchichal exceptions. But since this is something that is not included in Perl, I try to use the 'Exception::Class' module. For some reasons it's hard for me to find a start. I've tried to write a simple script with a classic x/0 error:
#!/usr/bin/env perl use Exception::Class ( 'MyException' ); # try eval { (my $result = (23/0)) || 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->time; exit; } else { $e = Exception::Class->caught(); ref $e ? $e->rethrow : die $e; }

But the error is not catched by my custom exception handling, but by some system error. Output
perl "exception-class-test.pl" Illegal division by zero
but I look for
I feel funny
Any ideas?
thanks in advance.
ben

Replies are listed 'Best First'.
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."
      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
        Actually, yes, you are wrong. In this case (the file opening example), the exception will be thrown. My guess is that your handling code is wrong. I have never used Exception::Class so I don't know how it is wrong, but my guess is that the if condition is not triggered.


        -pete
        "Worry is like a rocking chair. It gives you something to do, but it doesn't get you anywhere."
        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
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.

      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 (κς,πμ,πλ)
        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?
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.

      The exception even happens before the eval block is entered. This is because perl calculates immediate expressions during compile time.

      That's only true for older perls:

      $ 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).

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.

      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.

        I hope it's helpful to someone to point out that your solution works in 5.10.0 but in 5.8.8 perl dies with the familiar "Illegal division by zero at foo line 5." error.

        In fact, pasting that into perl 5.8.8's standard input instead of putting it in a file exits the shell in which it was run. That may not be the sort of thing people appreciate from example code.