The Problems with .NET Exceptions

My current contract involves a lot of Java work. I’ve always been a big fan of Java, although my personal opinion is that C# and .NET are superior to Java in most ways. The step back to Java, then, has really highlighted many of the evolutionary improvements that Microsoft has taken in the construction of their new platform. I really miss things like properties, attributes, and the precompiler. I find myself yearning for #region so that I can make my code more readable. The lack of automatic boxing is annoying, and I despise Java’s CLASSPATH code location scheme. But there is one thing that Java pretty much nailed but .NET does exceptionally poorly: Exceptions.

You’ll hear strong opinions on both sides of the issue of declared exceptions, but I come down firmly on the side that declared exceptions are most definitely a Good Thing. No matter how you cut it, exception flow is part of modern programming. Unfortunately, it’s a part this is often overlooked, especially by novice programmers, and all-too-often even by experienced developers. There are two big advantages from declared exceptions.

First, it causes the compiler to enforce a part of interface design that is mostly forgotten. What exceptions can be thrown from a method is as much a part of the interface as the return type or the parameters. In .NET, though, exceptions are relagated to mere mention in the documentation. Even with Visual Studio .NET’s built-in auto-help finder thing (which I always turn off because it annoys the hell out of me), it’s way too easy to forget that your method might throw an exception. In Java, though, the compiler ensures that you won’t forget. It’s the same as when it ensures you are allowed to make an upcast assignment.

Second, declared exceptions force you to think about exceptions! That might sound redundant, but so be it. Exceptions and their flow through the system is rarely thought through correctly, even by experienced architects. Making the tools we use noisey about our deficiences is a sure way to help us improve.

Some of the naysayers will attempt to point out that declaring every exception that can occur in a method leads to an insane number of class names in your throws statement. Java makes an acceptable compromise that a certain subset of exceptions, namely those extending from RuntimeException, do not have to be declared in the throws clause. This allows extremely common exceptions, such as a NullPointerException, to be thrown without declaration. Some others might say that declared exceptions result in code that catches and ignores exceptions inappropriately, such as the following:

try
{
    // Do something dangerous.
}
catch (SomeDeclaredException e)
{
}

This is often done just to “shut up the compiler.” Only coders who lack understanding of exceptions would do such a thing without a carefully considered (and hopefully commented) reason. As I stated above, though, there is a definite lack of understanding of exceptions among developers, especially .NET developers; So we would likely see such code a lot in C#. But at least they would be thinking about it, and that’s the first step towards understanding it.

I only have one idea about why .NET doesn’t require declared exceptions. The .NET runtime is often very tightly bound to the underlying Win32 platform. The IJW (It Just Works) cool-as-hell black-magic that lets you transparently call native C++ from Managed C++ helps blur that boundary and promote that tight coupling. In the unmanaged world, exceptions can occur at any time and be of any type. In C++, you can throw anything at all as an exception, even a char* string constant. Perhaps the fuzzy nature of exceptions in that IJW world makes it impossible to always determine what exceptions could be thrown from a method?

The fact that J# does support this ability, though, seems to undermine that idea. It’d be really cool if the next version of the C# compiler would support something similar to J#, at least as an option. I’m not holding my breath, though.

No wait, there’s more. I’m not done with my rant yet!

The other thing about .NET exceptions is the utterly poor design of the exception hierarchy. Java neatly seperates catastrophic errors, which should never be handled, from merely exceptional conditions, that a developer might have some chance of handling correctly. It does this by separating the former into the Error class and the latter into the Exception class. The .NET hierarchy makes no such distinction, to its detriment. For example, the OutOfMemoryException class extends from SystemException, which is the same base class as IOException, SerializationException, XmlException, and a host of other exceptions that are generally not catastrophic. So if you are writing code, and you are required to handle all non-catastrophic errors, you are also roped into handling several catastrophic ones as well. The alternatives are to either write code in your catch block to re-throw the catastrophic exceptions, or write several different catch clauses for each non-catastrophic error in the hierarchy! Clearly, a better design of the hierarchy would have saved us from this problem altogether.

Okay, I’m done for now. I’ll get off my soapbox. But if you’re listening, Microsoft please please PLEASE fix your exception class hierarchy. It sucks. Period.