Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Re: eval to replace die? (Exceptions and Error Handling References)

by eyepopslikeamosquito (Archbishop)
on Oct 04, 2010 at 03:36 UTC ( [id://863236] : note . print w/replies, xml ) Need Help??


in reply to eval to replace die?

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.

Replies are listed 'Best First'.
Re^2: eval to replace die?
by hsmyers (Canon) on Oct 04, 2010 at 04:27 UTC

    I like the zero dependencies part. While poking about, I installed TryCatch and wasn't pleased with the more than 400 files that tagged along. Don't think I want to do that to folks using my module. No way to avoid some build up, but minimizing it is bound to be a good thing (™) I also read EPP 2nd and noticed the reference to use autodie; and the other modules— maybe this is the way to go. At least the Try::Tiny option; I'd just as soon avoid dragging anyone into using a more modern Perl unless I have to!

    --hsm

    "Never try to teach a pig to sing...it wastes your time and it annoys the pig."