sgifford has asked for the wisdom of the Perl Monks concerning the following question:
and plan on fixing it later, which only occasionally happens.my $obj = Some::Object->new() or die "Couldn't create Some::object - $!\n";
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:- Inherit from Ekahau::ErrHandler
- Implement an ERROBJ method which returns the error object.
- Create an error handler object in the constructor.
- 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.
- Indicate error with return $self->reterr("error message"), which will set the error message then return undef.
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:
to get that effect for all modules using Ekahau::ErrHandler.Ekahau::ErrHandler->set_errhandler(sub { die @_ } );
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: Thinking about module error handling
by Tanktalus (Canon) on Jun 13, 2005 at 22:46 UTC | |
by sgifford (Prior) on Jun 14, 2005 at 00:04 UTC |