Go: Error handling

Why I think that try() is the right solution.

I love Go for many reasons, but this part is still itching me: I postulate that this Go idiom is a burden on our mental capacity:

if err != nil {
        return nil

Error handling is at a tension between two different developer needs.

Go’s explicitness about error handling makes sure that errors are not falling through the cracks as easily as they might do in other languages where errors are implicitly propagated1. While many developers love Go’s explicitness, it is rather verbose for error handling, which has drawbacks:

(1) Humans are pattern matching machines. Whenever we see text whose shape resembles the error checking idiom, we have trained ourselves to quickly look away, at the more important code next to it. But bugs can hide even in repetitive parts of the code. If we’re not looking at the idiom anyway, the try() proposal might be the better option, as it de-duplicates the check.

(2) The error handling pattern takes much visual space. The idiom is necessarily interleaved with the code on the happy path. In many cases, the flow of reading a longer function is interrupted multiple times with the same 3-line code snippet.

Two different hats

I believe that reasoning about constructive code and reasoning about error handling code are two separate states of mind, and switching back and forth between these is straining and tedious2.

A consequence of this is: It might be more productive to spend less time on errors during an initial implementation, and to then address the error handling aspect in a separate pass over the code. It would be better if we could have two views of the code for these different modes of operation:

I think this would have been well solved with Robert Griesemer’s try() proposal. I’m still sad it didn’t go forward, but I’m glad the Go team is so careful about it.

Just because we have all already invested so much time into accepting this verbose way of error handling, that doesn’t mean it’s a good thing4.

  1. This is particularly true for languages with exceptions where all function calls may implicitly throw exceptions and bubble them up the stack. ↩︎

  2. It’s the same as trying to write a scientific article straight in LaTeX form: You can somehow do it, but the first formula will derail your train of thought so hard that the article will probably suffer from it. It’s a better option to write the article in a different medium and then do the translation to LaTeX in a separate step. ↩︎

  3. Explicitness is a stated goal in Go, after all. ↩︎

  4. The sunk cost effect is strong for programming languages! But then again, it’s much worse for C++. :) ↩︎