Bad advice on exceptions from Joel

Starting from some comments on my exception handling series of articles I run into a couple of blogs pointing to this post on joelonsoftware.com.
I think this is the worst advice on exception handling I have ever read, sorry Joel.
I know this is an old post, I know Joel is entitled to his own opinion and I know he has the right to write his code as he sees fit. But as an opinion leader he influences others. While many times I enjoyed his fun and well written articles on the business of software, this time I was pretty disappointed.

Basically he recommends returning error codes from methods instead of throwing exceptions. His justification for this advice is a parallel he draws between exception throwing and GOTO statements and he points to Edsger W. Dijkstra’s “Go To Statement Considered Harmful” paper.

But here is what Dijkstra actually wrote about this issue:

“The go to statement as it stands is just too primitive, it is too much an invitation to make a mess of one’s program. One can regard and appreciate the clauses considered as bridling its use. I do not claim that the clauses mentioned are exhaustive in the sense that they will satisfy all needs; but whatever clauses are suggested (e.g. abortion clauses) they should satisfy the requirement that a programmer independent coordinate system can be maintained to describe the process in a helpful and manageable way.”

The “abortion clauses” are “exception handlers” and while they are indeed hidden GOTOs they are acceptable as they are implemented in a very structured way in languages like Java, C#, C++ and many others. On the other hand all constructs in structured languages are implemented with hidden GOTOs underneath.

The big advantage brought by exception handling concepts in modern languages is the clear separation of the failure paths. Now programmers have a very specific and structured mechanism for error handling.

Joel thinks exceptions are worse than GOTOs because:

  1. They are invisible in the source code
  2. They create too many possible exit points

I fail to see how these problems are specific to exceptions and how they don’t apply to the proposed solution of returning error codes.

When I look at a piece of code I will know if various method/function calls return error codes only if I am a psychic. Without good documentation you are as helpless as with exception handling. I still remember inspections of piles of C/C++ code, written by naive programmers, where function calls were made with no checking of the returned error codes or the global variables used to keep transient error codes.

On the other hand in Java you still stand a chance if the methods/functions you call throw checked exceptions since the compiler will tell you about them (I know some programmers think checked exceptions are evil but that is another discussion).

The problem of too many exit points, while valid, is not a problem caused by exceptions. It is more a problem of programming style and very related to an understanding of the KISS principle. Even without exceptions one can have multiple return statements in a function. And with the “returning of error codes solution” you will likely get this kind of code from less experienced programmers.

Paraphrasing what Joel writes I could say: “Every time you call a function that can return an error code and you don’t check it on the spot, you create opportunities for surprise bugs caused by functions that terminated abruptly, leaving data in an inconsistent state, or other code paths that you didn’t think about.

One thing to realize is that no mater what solution you choose to deal with errors, this doesn’t change the nature of your problem: you still have to deal with them in the right context. And this is the big challenge, dealing with exceptions (or error codes) in the right context.

The “better alternative” recommended by Joel (return error codes) is full of problems (as he already admits in the article):

  • The domain results returned by the fucntion usually don’t leave any space for error codes
  • Avoiding the above problem means using “out” parameters (think about preparing the function call by allocating memory for the results and other pleasant activities).
  • Handling the errors means mixing the success path and the error paths in a very convoluted way
  • The code becomes ugly and complicated and the logic of the success path is hidden by all error code checking

All these problems seem, to Joel, more acceptable than structured exception handling. They don’t seem to me.

PS: If Joel changed his opinion in the 5 years since he wrote that post he should at least go back and put a warning there for his readers.

By the way, you can read a commented version of Dijkstra’s paper here.

This post is part of a series on exceptions:

  1. Thoughts on Java exceptions
  2. Some exceptions are more equal than others
  3. Less than perfect exceptions hierarchy
  4. Checked exceptions are priceless… For everything else there is the RuntimeException
  5. Design the failure case – Part 1
  6. Design the failure case – Part 2
  7. Exception design relativity
  8. Bad advice on exceptions from Joel

21 thoughts on “Bad advice on exceptions from Joel”

  1. “When I look at a piece of code I will know if various method/function calls return error codes only if I am a psychic.”

    Really?

  2. There is another alternative when using error codes: the return value is the status; the value that you’re looking for is passed in as a pointer. It tends to make the code cleaner and encourages the caller to check the status.

    The issue of “too many possible exit points” is, as you said, related to KISS. In a well-written function it shouldn’t be an issue because the exits are clear.

  3. Wow, that’s terrible advice.

    I’ve worked in places like that and in both cases the error handling was by far the worst part of the code, simply because adding a new error case in one tiny function might force changes to dozens of files, so people simply didn’t do it or would add a return code but not check it in most places that the function was called.

    Without stack traces, there were terrible problems dealing with bug reports in the field, too. You’d get a message like “file foo.txt locked during open (42)” but if foo.txt is a “popular” file it gives you no idea of who tried to open it the second time.

    I guess the worst part is “exceptions == gotos”. It’s something that sounds clever until you think about it for a bit – why doesn’t this apply to *any* programming construct? How does he think if, for, while, break, continue, case are achieved?

    I can understand to a certain extent why he doesn’t want exceptions in his C++ but to advocate never throwing exceptions in Java is simply irresponsible.

  4. I agree; worst Joel post of all time. I can’t believe he still thinks this though, despite the lack of a retraction.

  5. I’m never a big fan of Joel. He always seems to be closed in his own little mind circle. I think I only read one or two articles over the year or two I’ve been following his blog. I like exceptions. It allows you to focus more on your business logic. I do hate checked exception though. I never use them. You can always catch unchecked exceptions if you need to. Error code, IMHO, is just retarded.

  6. I’ve never really understood why so many people think Joel is an authority. Really you should take his advice with a grain of salt, keeping in mind the products he has experience working on. If you examine his site, he clearly has only limited experience developing software. Writing fairly simple old-school Windows applications is a far cry from writing scalable and robust cross platform applications.

  7. Joel.. after i read the stuff with “wassabi” and Java he lost all credibility about software development.. He may be good for some other stuff.

  8. I think that everyone’s advices should be taken ‘with a grain of salt’: Joel’s, McConnell’s and even Dijkstra’s!!!

    I completly agree on all technical points stated in this post although I think the tone used in it can start a flame war between those who like Joel and those who don’t.
    By the way, the former are still missing here …

  9. The primary problem with multiple exit points is that of mem allocation/deallocation and not KISS.
    (on the contrary – sometimes mutliple exit points makes it easier – esp for smaller functions)

    In java that really not as big a problem because of GC (it still is possible to leak though) but in C++/C things can get hairy if you have multiple exit points.

    eg.
    foo() {
    alloc mem
    if (some rare case) return;
    dealloc mem
    return
    }

    it is generally advisible to have exit points right at the beginning (guard checks) and at the end (return) of the function.

  10. Error handling in general is a challenge with any program. Making sure that the primary function of the program is clear, while still handling all of the error cases is not easy (I might go so far as to say that it is the most important open problem in programming). However I come down much closer to Joel’s opinion on this since in my experience exceptions make the easy cases easy, but make the difficult cases almost impossible.

    > 2. They create too many possible exit points
    > Even without exceptions one can have multiple return statements in a function.

    I think you miss the point. Some very good code (e.g. the PGP core crypto engine) has multiple exit points in many functions. This means that you can handle the simple case and then return so it is obvious that the function doesn’t do anything else, then you can go on to handle the next simplest case, and so on. This is actually a very good and very clear coding style if it is done properly.

    Asynchronous exceptions mean that any point can be an exit point, and additional work can be done between any two operations. Having six well defined exit points is not too many, but 600 possible (and invisible) exit points is. This means that it becomes very difficult to maintain any concept of state.

    Even if you stick to just synchronous exceptions you still have more possible exit points, and a more complicated state machine.

    > 1. They are invisible in the source code

    Perhaps you should look at the ComeFrom as a better comparator than GoTo. It’s possible to write a correct program using ComeFrom, and the success path might even be very clear, but it isn’t easy to get it right, and reading it can be very challenging.

    I see another problem with exceptions. If the exception handling routine has any side effects then you need to make sure that these changes can safely occur at any point in your program, and if the exception handling depends on the sate for the program then you need to make sure that it can handle any possible state.

    This means that locking problems become much more difficult, and state machines are almost impossible to define.

    > The big advantage brought by exception handling concepts in modern languages is the clear separation of the failure paths. Now programmers have a very specific and structured mechanism for error handling.

    Returning error codes up a few levels is effectively popping a stack. This is far more structured than any exception handler I’ve seen because you can make sure that things get properly cleaned up, and returned to a known state, as the various functions return up to a level that can handle the error.

    I agree with you that the ability to separate the error path is nice, but proper error handling path is just as complicated as the success path so separating the two makes it more difficult to make sure that structural changes to one are reflected in the other.

    > When I look at a piece of code I will know if various method/function calls return error codes only if I am a psychic.

    I’m sorry, but this is nonsense. Any function can return an error, and you need to write your program to assume that at some point in time any function will return an error. If you already know the outcome of any decision in your code, then you can delete the conditional statement.

    > …where function calls were made with no checking of the returned error codes…

    The fact that some programmer are idiots isn’t a good argument one way or another — it doesn’t matter what tools you give a fool the results will still be foolish. I will give you that exceptions make it easier for a bad programmer to pretend that all the possible error cases are handled, but it is much more difficult to actually make sure that all the errors are handled for all possible program states because exceptions can be called in the middle of functions so there

    Tom Cargill wrote an nice piece with some examples of how exception handling can give a false sense of security.
    http://www.informit.com/content/images/020163371x/supplements/Exception_Handling_Article.html

  11. where is the shoker? his c++ programmer so performance goes first, it doesnt matter how small performance gain is as long there is even 1 ns.

  12. Actually, Joel is right on the money.

    This is mostly because of the lack of garbage collection in C++, there are too many ways to make mistakes with exceptions.

    Error codes are of course bad, but they are the least bad choice.

  13. Saying don’t use exceptions in C++ because it doesn’t have garbage collection is just FUD. Anyone saying that either doesn’t code C++, or codes C and calls themselves a C++ programmer.

    If you can’t handle smart pointers, STL containers or ptr container wrappers (either your own or from the boost library) and the like, then just stick to a garbage collected language, but please just leave C++ out of it as you clearly have no idea what you are talking about.

  14. @Imp: I just realized you said everything I’m about to say, but more eloquently. But since I spent my lunch hour walk thinking about this, I’m posting my reply anyway.

    If an exception it thrown, 9 times out of 10, it’s because something went wrong in your program. When this happens, I want all the state changes that occurred to be rolled back.

    If you catch an exception far away from the point at which it was raised, it means that the methods in between had no interest in handling it. There are two cases where this would hold:
    1. either the methods are executing additional code for side effects, or
    2. the methods are computing some values to return in addition to the value computed by the method which raised the exception.

    I try to avoid case 1, since this would leave the program with a possibly incomplete state change. Case 2 is a possibility, but in that case you should rather be returning an error code or something like Haskell’s Maybe – such a return value could be checked by one of the in between methods to decide whether to continue computing an additional return value or to abort.

  15. @Ben, Stephen wasn’t deliberately attacking C++. He has a point: out of all the existing C++ code bases, very few pervasively use smart pointers or the STL. Give more credit to other people; not everyone is a clueless basher.

  16. Damnit. I wrote “not everyone is a clueless [programming language name] basher”, but with angle brackets and it got nuked :).

  17. Dijkstra wrote that GOTO opinion piece in 1968, when use of the GOTO statement was overabundant and did cause a mess. Today, using the GOTO statement is quite acceptable and will even find its usage in things such as the Linux kernel.

    When used right, GOTO statements are much more readable than any alternative I can think of. I’d never give it up.

    -Jer

Comments are closed.