I doubt that PBP (2005) is up to date with the latest developments in this area.
The recently released (2010) 2nd edition of
Effective Perl Programming by brian_d_foy recommends the CPAN
Try::Tiny module (released 2009)
and the new core autodie pragma (added to perl 5.10.1 in 2009): see items 101 ("Use die to generate exceptions") and 103 ("Handle exceptions properly").
In particular, item 103 summarizes with "handling $@ is tricky, but Try::Tiny does it correctly".
Note that Try::Tiny has zero dependencies.
2015 update: The excellent Modern Perl book by chromatic
also recommends Try::Tiny; from its "Style and Efficacy" chapter, "Exception Caveats" sub-section:
Using $@ correctly requires you to navigate several subtle risks:
- Unlocalized uses further down the dynamic scope may modify $@
- It may contain an object which overrides its boolean value to return false
- A signal handler (especially the DIE signal handler) may change $@
- The destruction of an object during scope exit may call eval and change $@
use feature 'try' (2023 update: for perl 5.38+)
As clarified with a complete perl v5.38 example program,
note that perl v5.34 added try/catch syntax, inspired by Syntax::Keyword::Try:
use feature 'try';
try {
do_a_thing();
}
catch ( $e ) {
warn "It failed - $e";
}
perl v5.36 added finally blocks to try/catch, also inspired by Syntax::Keyword::Try:
use feature 'try';
try {
do_a_thing();
}
catch( $e ) { ... }
finally {
cleanup();
}
Some perldoc References
- die - is how you throw exceptions in Perl
- eval - used to execute a little Perl program, trapping any errors encountered so they don't crash the calling program
- Carp - alternative warn and die for modules
- autodie - Replace functions with ones that succeed or die with lexical scope
- Fatal - Replace functions with equivalents which succeed or die
Exception Safety and RAII
RAII (Resource Acquisition is Initialization)
is very useful when throwing exceptions in Perl (via die).
To give a very simple example, this code:
use strict;
use warnings;
sub fred {
my $fname = 'f.tmp';
open( FH, '<', $fname ) or die "error: open '$fname': $!";
print "file '$fname' opened ok\n";
# ... process file here
die "oops"; # if something went wrong
close(FH);
}
my $ok = eval { fred(); 1 }; # see [id://11130946]
if (!$ok) { print "died: $@\n" }
# oops, handle FH is still open if an exception was thrown.
my $line = <FH>;
print "oops, FH is still open:$line\n";
is not exception-safe because the global file handle
FH is not closed when die is called.
A simple remedy is to replace the ugly global FH with a lexical file handle $fh,
which is auto-closed at end of scope (RAII):
use strict;
use warnings;
sub fred {
my $fname = 'f.tmp';
open( my $fh, '<', $fname ) or die "error: open '$fname': $!";
print "file '$fname' opened ok\n";
# ... process file here
die "oops"; # if something went wrong
close($fh);
}
my $ok = eval { fred(); 1 }; # see [id://11130946]
if (!$ok) { print "died: $@\n" }
print "ok, \$fh is auto-closed when sub fred exits (normally or via di
+e)\n";
References Added Later
Some useful recent Perl Monks nodes:
Some general advice from On Coding Standards and Code Reviews (API Design Checklist section):
- Error handling. Document all errors in the user's dialect. Prefer throwing exceptions to returning special values. Prefer to find errors at compile time rather than run time.
As noted at On Interfaces and APIs:
- Perl 5's "string eval" and "block eval" is an example of violation of the "principle of distinction", aka "different things should look different"
Some older nodes:
Some external references:
CPAN Modules:
- Syntax::Keyword::Try by Paul Evans - a try/catch/finally syntax for perl
- Syntax::Keyword::Defer by Paul Evans - execute code when leaving a block (via a defer block)
- Feature::Compat::Try by Paul Evans - make try/catch/finally syntax available. On older versions of perl before such syntax is available, it is provided instead using the Syntax::Keyword::Try module.
- Feature::Compat::Defer by Paul Evans - make defer syntax available. On older versions of perl before such syntax is available, it is provided instead using the Syntax::Keyword::Defer module.
Wikipedia:
ISO C++:
- Exceptions and Error Handling (As a rule of thumb, exception handling is extremely cheap when you don't throw an exception. It costs nothing on some implementations. All the cost is incurred when you throw an exception: that is, "normal code" is faster than code using error-return codes and tests. You incur cost only when you have an error)
SO:
See Also
Updated: added use feature 'try' and Exception Safety and RAII sections.
Updated sample code based on Re: Bug in eval in pre-5.28.