It dawned on me that I've never seen a single exception hierarchy for which creating subclasses but catching the parent class was actually useful (except, of course, for the base Exception class, that has to be derived).
Are exception hierarchies really useful, xor should all exceptions be derived from language's base exception class?
Exception hierarchies are useful for grouping related exceptions together, when you need different granularity of catching in different places.
Putting all application exceptions in one place is the commonest use case. This allows you to catch
MyAppException
any time that you want to trap all errors coming from your application, but still catch more specific exceptions when appropriate. (In .NET, theApplicationException
class was meant for this, but it's been deprecated for various reasons.)But you can also group exceptions together at module boundaries, or in any other way that makes sense. Use
FooModuleException
for exceptions coming from theFoo
module, but catch and handleFooModuleMustFrobnicate
specially internal toFoo
. Or any equivalent situation.I've used all of these patterns at different times.
TL;DR
Error
) and "normal" runtime exceptions. The notion that "you need different granularity of catching in different places" is IMHO fundamentally flawed. (Except, to reiterate, to differentiate between exceptions and assertions and other system wide unrecoverable stuff.)I am slowly coming to consider the whole concept of arbitrarily typed exceptions, as I see them implemented and supposed-to-be-used in C++, C# and Java as totally useless.
The problem is not so much the exception hierarchy per se, but that when I write code, and exception are exceptional, I don't care what type of exception was thrown for the purpose of catching it.
In all my coding in C++, Java and C#, I found -- for the exceptional exceptions, that were not misused for control flow -- not one case where I wanted to filter (i.e. catch or not catch) the exceptions by their "hierarchical" type. That is, there are rare cases where a function throws 3 different exceptions, and I want to specifically handle one of them, and handle the two others as general "fail" (like described below) but I never ever encountered this in a case where the exception hierarchy was useful in that I could meaningfully group the two cases by base classes.
If any operation (where I care) in my program fails with any exception, then this operations is considered failed, and:
recover, etc.)I think Java is the only of the three languages that at least has the right approach with their hierarchy, namely:
Throwable
not used in user codeError
the stuff you never want to catch - just core dumpException
- for all the stuff you basically always want to catch (except for when an Interface is botched and uses an Exception when it really shouldn't)//
The hierarchy of C++'s
<stdexcept>
has the right basic approach in differentiating betweenlogic_error
- basically assertions - andruntime_error
- stuff that just unexpectedly failed. (The subclasses of theses are largely irrelevant when catching.)Except of course that too much stuff derives directly from
std::exception
so you can't make use of the differentiation provided by runtime and logic error. (And of course any code is free to throw whatever they want, so chances are good that there's a bunch of logic_error derived classes that really should be runtime_errors and vice-versa.To quote another answer:
but in my experience I never want "catching in different places", because it just doesn't make sense.
I either want catching, in which case I catch everything (modulo stuff like the
Error
class exceptions from Java) or I don't want to catch, in which case the hierarchy is not needed, because there is no catch.Take opening and reading from a file:
If there is (would be) any exception type I specifically care about, because I can do something about it ("recover"), then this should not be reported as an exception at all, because it is normal control flow. (If the error is such-and-such, I can do such-and-such basically locally.)
If on the other hand, I can't do anything about an error but record the file operation as failed, then having any catch granularity is utterly useless.
I've never created a single exception hierarchy for whole application, because an exception in general can bring different semantic and, therefore, needs to handled differently.
Some exceptions inform about system faults, another exceptions inform about bugs, and some other - about some exceptional condition, that could be gracefully recovered on higher level.
For this "business-logic" exceptions exception hierarchy can help you not to violate open-closed principle during overriding some methods in descendants.
Consider following example:
Exception hierarchy may be helpful in custom framework or in specific libraries, but in general case (in business applications) I don't think that creating one deep and wide exception hierarchy is a good idea.