Checked vs Unchecked vs No Exception… A best practice of contrary beliefs

error handlingexceptions

There are many requirements needed for a system to properly convey and handle exceptions. There are also many options for a language to choose from to implement the concept.

Requirements for exceptions (in no particular order):

  1. Documentation: A language should have a mean to document exceptions an API can throw. Ideally this documentation medium should be machine usable to allow compilers and IDEs to provide support to the programmer.

  2. Transmit Exceptional Situations: This one is obvious, to allow a function to convey situations that prevent the called functionality from performing the expected action. In my opinion there are three big categories of such situations :

    2.1 Bugs in the code that cause some data to be invalid.

    2.2 Problems in configuration or other external resources.

    2.3 Resources that are inherently unreliable (network, file systems, databases, end-users etc). These are a bit of a corner case since their unreliable nature should have us expect their sporadic failures. In this case are these situations to be considered exceptional ?

  3. Provide enough information for code to handle it: The exceptions should provide sufficient information to the callee so that it can react and possibly handle the situation. the information should also be sufficient so that when logged this exceptions would provide enough context to a programmer to identify and isolate the offending statements and provide a solution.

  4. Provide confidence to the programmer about the current status of his code's execution state: The exception handling capabilities of a software system should be present enough to provide the needed safeguards while staying out of the way of the programmer so he can stay focused on the task at hand.

To cover these the following methods were implemented in various languages:

  1. Checked Exceptions Provide a great way to document exceptions, and theoretically when implemented correctly should provide ample reassurance that all is good. However the cost is such that many feel it more productive to simply bypass either by swallowing exceptions or re-throw them as unchecked exceptions. When used inappropriately checked exceptions pretty much looses all it's usefulness. Also, checked exceptions make it difficult to create a API that is stable in time. Implementations of a generic system within a specific domain will bring it's load of exceptional situation that would become hard to maintain using solely checked exceptions.

  2. Unchecked Exceptions – much more versatile than checked exception they fail to properly document the possible exceptional situations of a given implementation. They rely on ad-hoc documentation if at all. This creates situations where the unreliable nature of a medium is masked by an API that gives the appearance of reliability. Also when thrown these exceptions loose their meaning as they move back up through the abstraction layers. Since they are poorly documented a programmer cannot target them specifically and often needs to cast a much wider net than necessary to ensure that secondary systems, should they fail, do not bring down the whole system. Which brings us right back to the swallowing problem checked exceptions provided.

  3. Multistate return types Here it is to rely on a disjoint set, tuple, or other similar concept to return either the expected result or an object representing the exception. Here no stack unwinding, no cutting through code, everything executes normally but the return value must be validated for error prior to continuing. I have not really worked with this yet so cannot comment from experience I acknowledge it resolves some problems exceptions bypassing the normal flow but still it will suffer from much the same problems as the checked exceptions as being tiresome and constantly "in your face".

So the question is :

What is your experience in this matter and what, according to you is the best candidate to make a good exception handling system for a language to have ?


EDIT:
Few minutes after writing this question I came across this post, spooky !

Best Answer

In the early days of C++ we discovered that without some sort of generic programming, strongly typed languages were extremely unwieldy. We also discovered that checked exceptions and generic programming didn't work well together, and checked exceptions were essentially abandoned.

Multiset return types are great, but no replacement for exceptions. Without exceptions the code is full of error-checking noise.

The other problem with checked exceptions is that a change in the exceptions thrown by a low-level function forces a cascade of changes in all the callers, and their callers, and so on. The only way to prevent this is for each level of code to catch any exceptions thrown by lower levels and wrap them in a new exception. Again, you end up with very noisy code.

Related Topic