> Exceptions are a reasonable model. The catch is that if
> someone uses the thing without realizing it dies then
> they can accidentally kill code above it. In that case
> you have to eval just about everything with checks for
> $@. This gets worse if you use blessed exceptions since
> evary eval has to check for ref $@ and bracnch accordingly.
See, that's just insane. The whole point of exceptions is that it's
supposed to kill everything above it. The function says "OMFG! This is
bad! I'm bailing out!"
You have two options:
1) identify the error and handle it properly when it occurs (or
prevent it from happening in the first place).
2) watch your program die and be happy that it didn't continue in a bad state.
Wrappering everything in evals and ignoring it is just friggin'
terrible and you might as well use error codes at that point. One of
the points of exceptions (IMHO) is that you don't need to add in error
handling code until you actually start handling the error. Error codes
lead to all sorts of bits of bubbling up logic:
sub foo {
my $self = shift;
my $bar_obj = $self->get_bar_obj;
$bar_obj->do_something_novel or return
$self->error_code($bar_obj->error_code);
}
and stuff like that. Copying the $bar_obj's error code into your own
slot so your caller can see it. Exceptions should work like this:
sub foo {
my $self = shift;
my $bar_obj = $self->get_bar_obj;
$bar_obj->do_something_novel;
}
And bam! You're done. Stick an eval in there if you can handle it, and
otherwise, assume that somebody else will. If you wrappered every call
that can die in an eval, you've just added needless additional clutter
at best and actually disabled your error handling at worst.
Yes, yes, there are modules that get a bit overzealous with the
die-ing and die for non-fatal errors, but that's a problem with their
interface, not with using exceptions.
Think about it - if you -know- that something bad has happened, why
would you want to continue? Why would you want to wrapper every single
method call you have with handler code to bubble it back up to a
higher point in the stack when the exception mechanism can handle it
for you? Either deal with it, or bail out.
Now, all that said, I tend to use error codes. I think Perl's syntax
for exception handling sucks. I -want- try/catch blocks, not
eval/die/if $@ mess. Further, I don't want to import a module to add
in syntax to the language into every single damn bit of code I have
just to add try/catch blocks. They should be built in.
But I also built the best of both worlds into Basset. There's a flag
you can set - enable_exceptions. By default it's off and everything
uses error codes. Flip it on, and everything uses exceptions instead.
Conceptually, it's easy - you have to write for error codes and bubble
up everything all over the place (adding clutter and mess), but once
they're there, you can internally change your error_code method to die
with the message (or object, or whatever) instead. The technique can
be applied anywhere.
I do think error codes are easier to insert, though. Plugging a module
that throws exceptions into an app that uses error codes can be
difficult. Plugging a module that uses error codes into an app that
uses exceptions tends to be easier. TIMTOWDI sucks in perl when it
comes to error handling. I value consistency very highly.
-Jim...