The Right Approach to Exceptions

Juan Manuel Cabo juanmanuel.cabo at gmail.com
Sun Feb 19 02:30:43 PST 2012


Hello D community! This is my first post!! I hope I can bring 
clarity to all this. If not, I apologize.

Some time ago I researched the best way to classify exceptions 
and build a hierarchy. I came up with the following rules:


1) At the top level, there would be RecoverableExceptions and 
FatalExceptions (or you can call them something like 
CatcheableException and FatalExceptions, or Exception and Error).

2) Fatal exceptions shouldn't be catched. They imply that the 
program lost basic guarantees to go on (memory corruption, 
missing essential file, etc.). You could catch them if you wanted 
to, but it makes no sense other than at your top-level method 
(main(), etc.).

3) A RecoverableException can be converted to a FatalException by 
rethrowing it, once a catch decides so. You shouldn't do the 
reverse: a FatalException never should be converted to a 
RecoverableException.

4) It makes no sense to subclass FatalExceptions since there 
won't be a catch that groups them in a base type (since they are 
not catcheable).

5) Only create a new RecoverableException class type if it makes 
sense to write a catch for it alone. Otherwise, use an 
preexisting type.

6) Only group RecoverableExceptions in a category if it makes 
sense to write a catch for that category. Please don't group them 
because its fancy or "cleaner", that is a bad reason.


Who decides when an Exception is Unrecoverable? Library code 
almost never decides it, since an exception is only unrecoverable 
if the whole_program_invariant got broken, and libraries are only 
a part of a program. So they will tend to throw 
RecoverableExceptions, which can be reconverted to Unrecoverable 
by the program.

In some cases, it is clear that an exception is Unrecoverable. 
When you call a function without satisfying its arguments 
precondition (ie: null argument) the only way to fix that is by 
editing the program. You shouldn't have called it like that in 
the first place, why would you? So you let the 
UnrecoverableException bubble up to your main function, and log 
its stacktrace to fix it.

Unrecoverable means the program got 'tainted', basic guarantees 
got broken (possible memory corruption, etc.). Most exceptions 
will be Recoverable.

Now, expanding on the hierarchy: I said that it makes no sense to 
subclass UnrecoverableExceptions. Recoverable exceptions on the 
other hand, need to be subclassed _with_the_catch_on_your_mind_. 
You are passing info from the throw site to the catch site. The 
catch block is the interpreter of the info, the observer. You are 
communicating something to the catch block.

So please, do not create a new types if there is no value in 
writing a catch that only cathes that exception and that can 
recover from that exception. Otherwise, use an existing type.


I wrote these rules some time ago. Please excuse me if they come 
off a bit pedantic!!!!!!!!!!!! Its all only a clarifying 
convention.


According to all this:

* FileNotFoundException is useful. It tells you what happened. It 
is a RecoverableException (under my convention) because until it 
reaches the program, the library doesn't know if the program can 
recover from that (it could be a system missing file, or just a 
document the user asked for).

* DiskFailureException is only useful if someone can write a 
catch for it. If so, then it is a RecoverableException. Only the 
program can decide if it broke basic guarantees.

* Most argument exceptions are Unrecoverable. A function throwing 
shouldn't have been called like that in the first place. The only 
fix is to go back to editing the program. (precondition broken).


Another thing: you cannot decide whether an exception is 
Unrecoverable based only on whether the thing that got broken is 
the postcondition of a function. It is the 
whole_program_invariant that decides that. For instance:  
findStuff(someStuff)  might not know if someStuff is important 
enough for the stability of the program if not found. The 
postcondition is broken if it doesn't return the Stuff. That 
might be recoverable.

And PLEASE: don't make classifications by the point of view of 
the cause of the problem. DO make classifications by the point of 
view of the fixing/recovery of the problem; the catch block is 
who you are talking to. FileNotFoundBecauseFilesystemUnmounted is 
worthless.

So, to sum up: (1) it makes no sense to subclass fatal 
exceptions, and (2) never subclass a RecoverableException if you 
are not helping a catch block with that (but please do if it aids 
recovery).

..so verbose and pedantic for my first post... yikes.. i beg 
forgiveness!!!




On Sunday, 19 February 2012 at 09:27:48 UTC, Jonathan M Davis 
wrote:
> On Sunday, February 19, 2012 19:00:20 Daniel Murphy wrote:
>> I wasn't really serious about implicit fallthrough.
>
> Lately, it seems like I can never tell whether anyone's being 
> serious or not online. :)
>
>> Out of the syntaxes I could come up with:
>> catch(Ex1, Ex2 e)
>> catch(e : Ex1, Ex2)
>> catch(Ex1 | Ex2 e) // java 7 syntax, horrible
>> 
>> I like (e : list) the best.  Naturally it would also accept a 
>> type tuple of
>> exceptions.
>> 
>> http://d.puremagic.com/issues/show_bug.cgi?id=7540
>
> LOL. Personally, I actually think that the Java 7 syntax looks 
> great (I'd never seen it before), but catch(e : Ex1, Ex2) is 
> just as good and more consistent with the language as a whole, 
> since it doesn't try to give any operators a new meaning (as 
> Java's does).
>
> - Jonathan M Davis




More information about the Digitalmars-d mailing list