I uploaded my little 2003 article on exception categorization to
github,
where I detailed my whole point_of_view_of_the_catch and
whole_program_invariant phylosophy for organizing clasess, and
compared
C++, .NET and Java hierarchies. Its not a professional article,
and I never wrote a translation to english:
https://github.com/jmcabo/ExceptionArticle/blob/master/articuloExcepciones_v2.pdf
--jm
On Sunday, 19 February 2012 at 10:30:45 UTC, Juan Manuel Cabo
wrote:
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