Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??
As seems to happen to all Perl programmers eventually, I've been thinking about error handling in modules I code. It seems like I always start off just returning undef or using die, then after a while want to know more information about why something failed, and end up writing some kind of half-assed error handling system, which I gradually expand. And this seems to be what everybody else does, so you have to wade through documentation to know whether a module has custom error handling code, uses variables like $! or $@, or just dies. I usually end up just writing things like:
my $obj = Some::Object->new() or die "Couldn't create Some::object - $!\n";
and plan on fixing it later, which only occasionally happens.

die and eval solve part of this problem, but it's annoying to have to wrap every constructor and method call inside of an eval block, and in general die should only be used for truly unexpected and exceptional conditions, not simple errors that may happen from time to time.

Realizing I was about to start coding another half-assed error handling system, I decided instead to try to put together something more flexible. My goals are:

  • Modules should be able to use it with minimal headache
  • Consistent and straightforward interface for module users.
  • Possible to use in a thread-safe way
  • Flexible

I've posted the code for my fellow monks' consideration and comments. I used it for a module called Ekahau, so it's called Ekahau::ErrHandler; of course it would be renamed if I uploaded it to CPAN.

Interface for Module Programmers

To make this as simple as possible for module programmers, there are only 5 simple requirements:
  1. Inherit from Ekahau::ErrHandler
  2. Implement an ERROBJ method which returns the error object.
  3. Create an error handler object in the constructor.
  4. Inform the error handling module when the object is constructed, so it can store error methods in the object instead of in a class-wide variable.
  5. Indicate error with return $self->reterr("error message"), which will set the error message then return undef.
For example, here's a typical usage:
package Some::Object; use base 'Ekahau::ErrHandler'; sub new { my $class = shift; my(%p) = @_; my $self = {}; bless $self,$class; $self->{_errhandler} = Ekahau::ErrHandler->errhandler_new($class,%p); return $self->reterr("An error happened") if ($error_happened); $self->errhandler_constructed(); } sub ERROBJ { my $self = shift; $self->{_errhandler}; }

User Interface

If an error is indicated by a constructor or method returning undef, the last error can be retreived with the lasterr method. If the error happened during a method call, you can get the last error for that object with $obj->lasterr; if the constructor failed, you can use Class->lasterr to get the last constructor error.

That means you can do:

my $obj = Some::Object->new() or die "Couldn't create Some::Object - ".Some::Object->lasterr; $obj->method_call() or die "Couldn't method_call $obj - ".$obj->lasterr;

Customizing

You can customize the error handling at three levels: for a particular object, for a specific class, and for all classes which use Ekahau::ErrHandler. There are two types of customization currently supported.

First, you can use the set_errholder method or the ErrorHolder constructor argument to give a reference to a scalar where errors can be stored. This can make those die statements more readable, but more importantly can be used for threadsafe error handling, since it avoids using a global variable shared across all threads. For example:

my $err; my $obj = Some::Object->new(ErrorHolder => \$err) or die "Couldn't create Some::Object - $err\n"; $obj->method_call or die "Couldn't method_call $obj - $err\n";

Second, you can use set_errhandler to set your own error handler that should be called when a module encounters an error. For example, if you prefer to use eval/die for your error handling, you could use:

Ekahau::ErrHandler->set_errhandler(sub { die @_ } );
to get that effect for all modules using Ekahau::ErrHandler.

In reply to Thinking about module error handling by sgifford

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (4)
As of 2024-03-29 11:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found