Biz & IT —

What’s preferable: Exceptions or explicit error testing?

A burning question from efficiency and security standpoints.

What's preferable: Exceptions or explicit error testing?
Stack Exchange
This Q&A is part of a weekly series of posts highlighting common questions encountered by technophiles and answered by users at Stack Exchange, a free, community-powered network of 80+ Q&A sites.

Richard Keller asks:

I often come across heated blog posts where the author uses the argument: "exceptions vs explicit error checking" to advocate his/her preferred language over some other language. The general consensus seems to be that languages that make use of exceptions are inherently better / cleaner than languages which rely heavily on error checking through explicit function calls.

Is the use of exceptions considered better programming practice than explicit error checking, and if so, why?

Note: The featured question is now closed on Stack Exchange. Please consider leaving an answer at the similar question: "Defensive programming vs. exception handling?"

Answer: Write Clear & Safe with Exceptions (49 Votes)

Steven Schlansker replies:

In my mind, the biggest argument is the difference in what happens when the programmer makes an error. Forgetting to handle an error is a very common and easy mistake to make.

If you return error codes, it is possible to silently ignore an error. For example, if malloc fails, it returns NULL and sets the global errno. So correct code should do

void* myptr = malloc(1024);
if (myptr == NULL) {
perror("malloc");
exit(1);
}
doSomethingWith(myptr);

But it is very easy and expedient to instead only write:

void* myptr = malloc(1024);
doSomethingWith(myptr);

which will unexpectedly pass NULL into your other procedure and likely discard the errno which was carefully set. There is nothing visibly wrong with the code to indicate that this is possible.

In a language that uses exceptions, instead you would write

MyCoolObject obj = new MyCoolObject();
doSomethingWith(obj);

In this (Java) example, the new operator either returns a valid initialized object or throws OutOfMemoryError. If a programmer must handle this, they can catch it. In the usual (and conveniently, also the lazy) case where it is a fatal error, the exception propagation terminates the program in a relatively clean and explicit manner.

That is one reason why exceptions, when properly used, can make writing clear and safe code much easier. This pattern applies to many, many things which can go wrong, not just allocating memory.

Answer: Refactor & Avoid Boiler Plate with Exceptions (43 Votes)

Simon replies:

While Steven's answer provides a good explanation, there is another point which I find is rather important. Sometimes when you check an error code, you cannot handle the failure case immediately. You have to propagate the error explicitly through the call stack. When you refactor a big function, you may have to add all the error checking boiler plate code to your subfunction.

With exceptions, you only have to take care of your main flow. If a piece of code throws some InvalidOperationError, you can still move that code to a sub function and the error management logic will be maintained.

So exceptions allow you to refactor faster and to avoid boiler plate.

Related: "The modern way to perform error handling…"

Answer: Error Handling is a Matter of Security (6 Votes)

Secure replies:

A point of view from a different angle: Error handling is all about security. An unchecked error breaks all assumptions and preconditions the following code was based on. This may open a lot of external attack vectors: From a simple DoS over unauthorized data access to data corruption and complete system infiltration.

Sure, it depends on the specific application, but when assumptions and preconditions are broken, then all bets are off. Within a complex software, you simply can't say anymore with certainty what is possible from then on, and what can and can't be used from extern.

Given that, there is a fundamental observation: When security is treated as an optional add-on that can be attached later, then it fails most often. It works best when it was already considered in the very first basic design stages and built-in right from the start.

This is what you basically get with exceptions: An already built-in error handling infrastructure that is active even if you don't care. With explicit testing, you have to build it yourself. You have to build it as a very first step. Just beginning to write functions that return error codes, without thinking about the big picture until you're in the final stages of your application development, is effectively an add-on error handling, doomed to fail.

Not that a built-in system helps in any way. Most programmers don't know how to do error handling. It's just too complex most of the time.

  • There are so many errors that can happen, and each error requires its own handling and its own actions and reactions.
  • Even the same error can require different actions, based on context. What about a File Not Found or an Out Of Memory?
    • FNF - A third party library needed for your app to run? Terminate.
    • FNF - The start-up config file of your application? Start with default settings.
    • FNF - A data file on a network share the user wants your app to open? Disappearing files can happen anytime, even in the microseconds between Exists() and Open(). It's not even an "Exception" in the literal meaning of the word.
    • OOM - For a 2GB allocation? No surprise.
    • OOM - For a 100 byte allocation? You're in serious trouble.
  • Error handling leaks through all your carefully separated abstraction layers. An error in the lowest level may require notifying the user with a GUI message. It may require a decision from the user on what to do now. It may need logging. It may need recovery operations in another part, e.g. open database or network connections. Etc.
  • What about state? When you call a method on an object that invokes state changes and it throws an error:
    • Is the object in an inconsistent state and needs a rebuild?
    • Is the object state consistent but (partially) changed and needs an additional rollback or a rebuild?
    • Is a rollback done within the object and it remains unchanged to the caller?
    • Where is it even sensible to do what?

Just show me one learner's book where error handling is rigorously designed from the start and consequently used through all the examples, without being left out for brevity and readability and as exercise for the reader. If this is applicable from an educational POV, that is another question, but it's no surprise that error handling is often enough a second or third thought when it should be the very first.

Think you know why exceptions are preferable to error testing? Disagree with the opinions expressed above? Bring your expertise to Stack Exchange, a network of 80+ sites where you can trade expert knowledge on topics like web apps, cycling, patents, and (almost) everything in between.

Channel Ars Technica