by Neil Fraser, January 2005
Most programming languages allow one to catch execution errors and gracefully recover from them. This is an extremely useful ability which if used properly can improve reliability and simplify programming. Unfortunately this ability can also be abused, leading to less reliable software and more complicated maintenance. This paper looks at both sides of the issue.
Examples of exception handling in various languages:
"Do or do not; there is no try." -- Yoda
Exception handlers can be a dangerous tool. They are capable of causing errors which are extremely difficult to debug.
Just like COME FROM, exception handling can also produce unexpected and non-linear flow. A program may be executing normally, then suddenly program flow jumps several levels up the call stack and resumes somewhere else. An exception handler which was added to deal with a particular event (say, a divide by zero), sometimes ends up suppressing all similar events within a large area. It can be very difficult to debug a program where the root cause of a bug is inadvertently being squelched by someone else's exception handler.
Exception handling is often used as the lazy way out of a problem. Not sure exactly why something is failing intermittently? Don't bother investigating, just trap the error and keep going. If it's important, someone else can fix it properly later.
try {
file_open(filename)
file_write(filename, data)
file_close(filename)
} catch (FILE_ERROR) {
print("Sorry, can't save.")
}
Now look what happens if the file is read-only: file_open() executes
fine, file_write() fails, execution jumps to the error message, then the
program continues to run. Everything is fine except that one file handle
has been left open. If this code is in a loop or is in a long-running
application one starts to leak file handles. Eventually the operating
system runs out of file handles and random applications running on the
same computer start to crash.
The problem with relying on exception handlers is that code is being stressed in ways that it may not have been designed for. A function might normally be very careful to deallocate all the memory which it requested, but if execution jumps out half way through the function due to invalid inputs, one is left with a memory leak. A function might increment a global reference counter then explode (and be caught) while creating the invalid item, thus leaving the data out of synch. Unless a function has been designated as being "exception-safe", it is wiser to check the inputs before calling the function rather than wrap the function in an exception handler.
"I'll try anything once." -- Darwin Award Winner
Exception handlers can be a valuable tool. They are capable of increasing reliability and simplifying code.
Before shipping an important program, it is often wise to enable a global exception handler that suppresses any unknown errors and lets the application attempt to continue to running when something does go wrong. Such a handler should log the error and alert the user that now would be a really good time to save any data and restart. However, this global handler should not be active during project development or testing. Otherwise it just serves to hide errors from the very people who are supposed to fix them.
This is exactly what exception handling is designed for. First check for the obvious things like an empty file name, then attempt to save the file and trap any errors. Exception handling allows one to keep the code simple, yet still deal reasonably well with unexpected events.
Exception handlers are reasonably good at providing isolation between an application and 3rd party code. This is especially wise if the 3rd party code might be updated at a later date, or might exist in various versions on the end users' computers.
Unfortunately many programmers pick up the habit of using exception handlers in quick and dirty situations like this, then continue using them in the same way when they migrate to writing more substantial code.
Exception handling is an important tool for programmers. But it can be, and often is, used inappropriately. "GOTO" was once a valuable tool, but we abused it and as a result it was taken away from us. If programmers continue to abuse exception handlers in the same way, exception handling will acquire a bad name and it will eventually be taken away. I find it helpful to think of an exception handler as an ejection seat: use it to save yourself in an emergency, but do not use it for routine issues. Think twice before using an exception handler.