Handling Exceptions (Perl Cookbook, 2nd Edition)

## 10.12. Handling Exceptions

### 10.12.1. Problem

How do you safely call a function that might raise an exception? How do you create a function that raises an exception?

### 10.12.2. Solution

Sometimes you encounter a problem so exceptional that merely returning an error isn't strong enough, because the caller could unintentionally ignore the error. Use `die` `STRING` from your function to trigger an exception:

>     die "some message";         # raise exception

The caller can wrap the function call in an `eval` to intercept that exception, then consult the special variable `$@` to see what happened:

>     eval { func( ) };
>     if ($@) {
>         warn "func raised an exception: $@";
>     }

### 10.12.3. Discussion

Raising exceptions is not a facility to be used lightly. Most functions should return an error using a bare `return` statement. Wrapping every call in an exception trap is tedious and unsightly, removing the appeal of using exceptions in the first place.

But, on rare occasions, failure in a function should cause the entire program to abort. Rather than calling the irrecoverable `exit` function, you should call `die` instead, which at least gives the programmer the chance to cope. If no exception handler has been installed via `eval`, then the program aborts at that point.

To detect this, wrap the call to the function with a block `eval`. The `$@` variable will be set to the offending exception if one occurred; otherwise, it will be false.

>     eval { $val = func( ) };
>     warn "func blew up: $@" if $@;

Any `eval` catches all exceptions, not just specific ones. Usually you should propagate unexpected exceptions to an enclosing handler. For example, suppose your function raised an exception containing the string "`Full` `moon!`". You could safely trap that exception while letting others through by inspecting the `$@` variable. Calling `die` without an argument uses the contents of `$@` to construct a new exception string.

>     eval { $val = func( ) };
>     if ($@ && $@ !~ /Full moon!/) {
>         die;    # re-raise unknown errors
>     }

If the function is part of a module, consider using the Carp module and call `croak` or `confess` instead of `die`. The only difference between `die` and `croak` is that with `croak`, the error appears to be from the caller's perspective, not the module's. The `confess` function, on the other hand, creates a full stack backtrace of who called whom and with what arguments.

Another intriguing possibility is for the function to detect that its return value is being completely ignored because the function was called in a void context. If that were returning an error indication would be useless, so raise an exception instead.

>     if (defined wantarray( )) {
>             return;
>     } else {
>         die "pay attention to my error!";
>     }

Of course, just because it's not voided doesn't mean the return value is being dealt with appropriately. But if it is voided, it's certainly not being checked.

There are CPAN modules that offer alternative ways of handling exceptions. The Error module offers `try`, `catch`, and `throw` notation instead of `eval` and `die`:

>     use Error ':try';
>     try {
>        something( );
>     }
>     catch Error::Database with {
>        my $e = shift;
>        warn "Problem in " . $e->{'-database'} . " (caught)\n";
>     };

Error offers `try`, `catch ... with`, `except`, `otherwise`, and `finally` blocks for maximum flexibility in error handling. The Exception::Class module from CPAN lets you create classes of exceptions and objects to represent specific exceptions. The two modules can be combined so that you can `catch` these exception objects.

### 10.12.4. See Also

The `$@` (`$EVAL_ERROR`) variable in Chapter 28 of Programming Perl and perlvar(1); the `die` and `eval` functions in Chapter 29 of Programming Perl and perlfunc(1); the documentation for the CPAN modules Error and Exception::Class; Recipe 10.15; Recipe 12.2; Recipe 16.21

Copyright © 2003 O'Reilly & Associates. All rights reserved.