Exceptions – 3

In my last post I presented a classification of exceptions by two Microsoft employees that should know what they are talking about. Here, I want to pick off the low hanging fruit and discuss just one of the categories of exceptions. A category that should not be caught.

Usage Errors” / “Boneheaded Exceptions” (also: Preconditions)
It may sound strange at first to say that any category of exceptions should never be caught. All documentation on exceptions keeps drilling home the message that exceptions exist to be caught and handled; unfortunately that isn’t true.

This category of exceptions serves the sole purpose of notifying the programmer that a method cannot be validly called with the given arguments and/or in the current state of the object it is called on. It signals that the programmer did not honour the preconditions of the method.

Handling such an exception is putting the cart before the horse. Let’s say we have the following method (note that the non-null condition is purely by way of a simple example; a better implementation would gracefully handle null strings):

/// <summary>
/// Manipulate a string in some fashion
/// </summary>
/// <param name="value">
/// The string to manipulate, must be non-null
/// </param>
/// <returns>The manipulated result</returns>
public string SomeMethod(string value);

And we use this method in some code, only to discover later that due to logic elsewhere nulls can end up making their way to this method. After careful analysis, it turns out for null values we want the result also to be null, so the following code fragment is written:

string result;
try
{
    result = SomeMethod(someValue);
}
catch (ArgumentNullException)
{
    result = null;
}

See? All fixed. Isn’t it wonderful how we are handling the exception, and everything is perfect, right?

Of course this is wrong. The correct way to deal with this situation is to not violate the precondition in the first place and just do it right:

string result =
    someValue == null
    ? null
    : SomeMethod(someValue);

Whenever you feel tempted to handle a “Usage Error” / “Boneheaded Exception” you should immediately wonder why the code isn’t checking the precondition, or alternately designed to honour the precondition by definition.

Letting these exceptions fall out of your application is not a sign that you forgot to add an exception handler. It’s a sign that you didn’t write the code correctly. Rather than spending time writing exception handlers, put that time into guard conditions on the call. Not only will it make your assumptions much more explicit, it also performs much better. An exception will typically take 1000s of times longer to process than an equivalent guard statement on your call.

Catching these exceptions doesn’t just indicate you’ve lost control of your code. It also signals that you don’t really care about performance at all.

So, what to do?
Because these exceptions are never intended to be caught but rather to tell the programmer that a precondition was not honoured, the exception class matters very little. What does matter is to make sure that the exception message is very explicit about the precondition that was not satisfied, and in what way it was not satisfied. Make the message as long and wordy as you need to, because a programmer will need to be able to read it, understand what the problem was, and then fix the code.

Although the type of the exception does not matter much, because a programmer is going to mainly go off the message, there are a few exception types in the .NET Framework that are specifically suitable to be used for these.

class ArgumentException
    class ArgumentNullException
    class ArgumentOutOfRangeException
    /// various others ...
class InvalidOperationException
    class ObjectDisposedException
    /// various others ...

Use “ArgumentException” or one of its sub-classes to signal when an argument to a method does not satisfy a precondition. Some recommend using the most derived class that is appropriate to the error that occurred, but as long as you make sure the exception message will make complete sense to the programmer it is fine to just use “ArgumentException” itself and no others.

Use “InvalidOperationException” or one of its sub-classes to signal when an object property does not satisfy a precondition to the method call being made. The same advice goes for sub-classes here as for “ArgumentException“.

By just using these two exception (trees) it also is very easy to make sure you never end up catching a “Usage Error” / “Boneheaded Exception”. Creating an FxCop rule that forbids these types occurring in exception handlers should be a breeze.

Also note that for reasons not related to exception semantics, “InvalidOperationException” should probably never occur. An API that could credibly throw this exception for the reason outlined above is very badly designed and should probably be refactored. (An example scenario is a class that has a flag to indicate a processing direction (input / output) and methods that only are allowed to be called for one of these modes. A better implementation would have a general base-class for shared functionality and then subclass into an input and an output class that each only have suitable methods on them.)

How to fix Boneheaded Handlers?
Whenever you encounter code that handles a Boneheaded Exception “X”, corresponding to precondition “P” that looks as follows:

try
{
    A;
}
catch (X)
{
    B;
}

Replace the code with the following instead:

if (P)
    B;
else
    A;

(Note that this assumes that exception ‘X’ actually corresponds to a precondition ‘P’, and gets thrown before any functional logic runs. Otherwise side-effects may make the transformation more complicated.)

Next post I’ll pick off the next-lowest-hanging fruit; “System Failures” / “Fatal Exceptions”.