Re: Best Practices for Exception Handling
by jonadab (Parson) on Jan 29, 2003 at 15:28 UTC
|
I tend to agree. A lot of people with a lot more
experience than I have rave about how wonderful exception
handling is, but they've failed to communicate to me
why it is valuable to be able to throw an exception in
one place and catch it someplace else rather than handling
the problem (assuming it can be handled by any means other
than spitting an error message and bailing) in the same
block of code where it is detected. It seems to me that
having the exception and the handling thereof separated
by arbitrarily many lines of code is asking for headaches
in terms of code maintenance. Rather than throwing the
exception in the first place, wouldn't it be better to
handle it en situ? (Sure, sometimes a number of spots
can share the same code -- so call a subroutine then,
but at least the call is right there.)
As I said, I have a good deal less experience than
a lot of the people who rave about exception handling,
so I'm probably missing something...
--jonadab
| [reply] [d/l] |
|
| [reply] [d/l] [select] |
|
> Robustness. I can forget to check for an returned
error value.
> I cannot forget to check for an exception.
> Brevity. I prefer: $o->foo->bar->fribble->ni
> to $o->foo or return(ERROR_FOO);
[snip]
Huh? Error return codes? Error return codes are
basically an inelegant way of doing exactly the same
thing -- punting the problem to some other code
someplace else. It's that whole approach that I
don't understand the value of. Points one, two,
and five all seem to be arguing against return
codes, which are in my view basically a certain
(particularly inelegant) type of exception handling.
You don't need to convince me that's a bad way to
do it; my question is why it (punting an error to
the caller's caller's caller) should ever be done
at all.
Regarding your third point, clarity: one of us
is smoking crack, because putting code that handles
an error pages away from where the error actually
happens is my idea of severe obfuscation. How it
could ever conceivably enhance clarity is entirely
beyond my ability to fathom.
Point four, however, I'd like to explore further.
Maybe I just haven't encountered the right problem
yet. Every error I've had to handle either could
be fixed, or it couldn't. If it couldn't be fixed,
it either could be logged and ignored and the
program proceed less certain functionality, or
else it was fatal. That basically leaves three
options when an error condition pops up: do
stuff to fix the problem, log it and go on, or
spit an error message and exit. I have yet to
encounter a situation where the caller might be
relevant to the question of which of these
conditions applies.
So, back to your point four: can you suggest
a real-world example or two of a situation where
the error needs to be handled differently depending
on where the routine is called or other circumstances
not known to the code that finds the error? I've
been through this discussion before (not here) and
have tried to imagine such a situation, but I can't
seem to come up with one.
--jonadab
| [reply] [d/l] |
|
|
|
|
|
I believe that the idea is that you can't always do something on the spot.
For example, suppose I am developing a flashcard application that reads flashcards from a file and displays them in a pretty window. To accomplish this, I decide to write a couple of classes that do the actual file reading and parsing, etc., in order to keep that separate from the gui code.
So what happens if, for example, the gui asks one of those objects to open a non-existant file? An elegant way out of the problem is for the object to raise an exception. The gui can then choose to catch that, and pop up a dialog, or whatever.
It is definitely not the *only* way to solve the problem, though. You could also, for example, have every method return error codes. Or a hash containing an error code plus whatever other value it wants to return. Exceptions do provide a very clean way to do it, though.
Just my $.02,
-Dan
| [reply] |
|
Java Boutique has an interesting article about exceptions that you might find useful.
What I like about exceptions is fairly straightforward. If I have a GUI (A) which issues a message to some object (B) which in turn sends a message requesting data from object (C), what happens if C determines that the data is bad due to user input (and not, say, a programming error)? There's probably no point in issuing a warning in the error log (because it's not an error from a programming standpoint) and there's no point in killing the application because a user typed something stupid (an all too common event, though).
In the above scenario, C throws in exception and B catches it. B then checks the exception to see if anything unusual needs to be done. If the exception is caused by failing to select a required option, no big deal. If the exception is caused by a bad password, perhaps it is a big deal. B can decide whether or not to log the exception and do further processing. B, at this point, rethrows the exception and A catches it. Because A is simply the GUI, A doesn't worry about logging the exception. A simply has to have some method of displaying the exception to the end user in a meaningful way.
Thus, with an exception based system, particularly if it's multi-tiered, you have full control of the error processing rather than simple die and warns. Further, uncaught exceptions will kill the program when encountered during execution, thus making them morely likely to be reported in testing and feedback -- which in turns means they are more likely to be handled appropriately and leads to more robust code.
Cheers,
Ovid
New address of my CGI Course.
Silence is Evil (feel free to copy and distribute widely - note copyright text)
| [reply] |
|
> If I have a GUI (A) which issues a message to some object (B) which
> in turn sends a message requesting data from object (C), what
> happens if C determines that the data is bad due to user input
See, that's where I always get lost. If C is getting
user input, and the user input is invalid, C should just
reget the user input. When it has valid input, it should
pass that back to B. Otherwise, it should continue to
ask the user to fix up the input.
In a slightly different scenerio, C might think the
input is okay (there's an integer in this integer
field, and some text in this required text field; C
does not know the meaning of these data, but they
are the kind of data that were requested),
but B might discover that it's inconsistent. (There
is no thirty-first of February.) In that case, B
would possibly explain the problem to the user and
then call C again; only when the input is good enough
for B to do its job does it then pass the result back
to A.
Do you see where I'm getting hung up? It's not with
the question of HOW to pass stuff back to the parent
(which was the original topic of the thread, I know),
but more with the more basic question of why that is
a thing that needs to be done. That's the point I
haven't managed to understand yet.
--jonadab
| [reply] [d/l] |
|
|
| [reply] |