Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Intelligent Exception Handling in Perl

by skyknight (Hermit)
on Jul 22, 2003 at 17:21 UTC ( [id://276830]=perlmeditation: print w/replies, xml ) Need Help??

Developer time is expensive, while machine time is becoming increasingly cheap. There are still development niches where squeezing every bit of performance out of the system is desirable, but more often then not it is better to implement code that is easy to maintain and facillitates the rapid detection and repair of code defects. Robust exception handling is at the core of this matter, and while Perl offers decent exception handling capabilities, it is not always clear the route to take.

At the simplest level, there is the eval/die idiom in which one wraps some code up in an eval block that may throw exceptions (try), and then afterward tests $@ and dies with some informative message should it be defined (catch). Just adding this simple methodology to one's code can be enormously helpful, but there are very different contexts in which one might want to throw exceptions, and accordingly different ways that may be appropriate. The Carp module offers some alternatives to 'die' with 'croak' and 'confess'.

Different exceptional cases may include invalid arguments passed to a subroutine, the unavailability of a file system or network resource, a subroutine in apparent violation of its contract, and many others. The error may have originated deep within underlying libraries, or it may be occuring right below the public interface of a class. Depending on the situation, it may be advantageous to throw an exception from the perspective of the caller, or to include a stack trace. One may also want to rethrow the exception to a higher level with additional information.

The correct route in some situations is more obvious than others. In the case of invalid arguments, it is probably advantageous to make the exception appear from the context of the caller with a helpful message such as "argument two was totally bogus, bozo!" In other scenarios, the best mechanism is less obvious. Always including a stack trace may seem advantageous at first glance, but in some contexts it may prove misleading, adding extra noise to the debug info and thus hindering detective work.

This would seem to be one of those things where there is WAY more than one way to do it, so I'd love to hear the heuristics that fellow Perl Mongers employ in their own daily coding when deciding on how to handle exceptions.

Replies are listed 'Best First'.
Re: Intelligent Exception Handling in Perl
by dragonchild (Archbishop) on Jul 22, 2003 at 18:12 UTC
    I use Error. I just discovered it about 2 months ago and I love it. The neatest thing about it is that it only comes with one error defined. You define your own errors, which means that your errors are meaningful to you. :-)

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: Intelligent Exception Handling in Perl
by Abigail-II (Bishop) on Jul 22, 2003 at 20:25 UTC
    In the fast majority of the code I write, I use plain old die, without wrapping them in eval. But this has more to do with the kind of programs I write than with a deeper philosophy. Most programs I write run quickly and are of the form "here's a bunch of things (files, arguments, environment variables, URLs), produce something". And the something can either be produced, or it can't. So, if there's something missing, or wrong, about the 'bunch of things', nothing should be produced, and the program should terminate with an error message. Which is exactly what die does.

    Programs performing database modifications do use another technique though. There I will do things like:

    eval { start transaction or die; ... prepare or die; ... execute or die; ... fetch or die; ... }; if ($@) { rollback; die $@; } else { commit; }

    If something goes, I die as usual, but this die will be caught, the transaction will be rolled back, and we cascade the die upwards (where it's most likely not caught again).

    Abigail

Re: Intelligent Exception Handling in Perl
by adrianh (Chancellor) on Jul 22, 2003 at 19:24 UTC
Re: Intelligent Exception Handling in Perl
by l2kashe (Deacon) on Jul 22, 2003 at 18:13 UTC

    This topic has been covered a few times recently. Relevant links can be found here, here, and here. (SuperSearch terms "Error Handling", though Im sure Exception would turn up a decent number of hits too.

    In my own code, I attempt to allow as much flexibility as possible in terms of how to handle errors. Though it is also directly related to what the code is supposed to do, and in what type of environment its run in.

    use perl;

Re: Intelligent Exception Handling in Perl
by hardburn (Abbot) on Jul 22, 2003 at 20:03 UTC

    I used Java before I started using Perl heavily. Whatever else you might say about the language, I must say that the exception handling is great. In Perl, Error.pm replicates much of Java's exception handling (and adds a few things of its own, but I've never used those parts so I can't comment on them).

    Back when I was doing Java, I realized that much of the time the exception classes are internally identical. You only need to seperate them from other exceptions for the benifit of the application.

    For instance, say you are using DBI, and you want to throw exceptions if it fails to connect, if a prepare() fails, or if an execute() fails. In one module I'm working on right now, I write three seperate exceptions for this, in the following inheirtance tree:

    • Error::Simple (already done for me)
      • My::DBException
        • My::DBPrepareException
        • My::DBExecuteException

    This is really easy to implement in Perl. At the bottom of my module, I declare all my exceptions like this:

    package My::DBException; use base 'Error::Simple'; package My::DBPrepareException; use base 'My::DBException'; package My::DBExecuteException; use base 'My::DBException';

    All the hard work was already done in Error::Simple. The application knows what went wrong because it has (should have) seperate catch . . . with { } blocks for each exception type.

    Note that the equivilent in Java requries having a seperate file for your exception (assuming it's used outside your specific class), inheirting from java.lang.Exception, and declaring your own constructor. This will take more than two-lines per exception. (Apoligies if any of the previous wasn't quite right--I've been away from Java for a while).

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    Note: All code is untested, unless otherwise stated

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://276830]
Approved by dga
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (3)
As of 2024-04-16 20:38 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found