PageRenderTime 25ms CodeModel.GetById 16ms app.highlight 7ms RepoModel.GetById 1ms app.codeStats 0ms

/_posts/2014-06-07-Why-Go-error-handling-doesnt-sit-right-with-me.md

https://github.com/SirCmpwn/sircmpwn.github.io
Markdown | 111 lines | 95 code | 16 blank | 0 comment | 0 complexity | 2825a4cb0af6c86ad8f5241b99e9f88c MD5 | raw file
  1---
  2#vim: tw=82
  3layout: post
  4title: Why Go's error handling doesn't sit right with me
  5---
  6
  7I'll open up by saying that I am not a language designer, and I do like a lot of
  8things about Go. I just recently figured out how to describe why Go's error
  9handling mechanics don't sit right with me.
 10
 11If you aren't familiar with Go, here's an example of how Go programmers might do
 12error handling:
 13
 14{% highlight go %}
 15result, err := SomethingThatMightGoWrong()
 16if err != nil {
 17    // Handle error
 18}
 19// Proceed
 20{% endhighlight %}
 21
 22Let's extrapolate this:
 23
 24{% highlight go %}
 25func MightFail() {
 26    result, err := doStuffA()
 27    if err != nil {
 28        // Error handling omitted
 29    }
 30    result, err = doStuffB()
 31    if err != nil {
 32        // Error handling omitted
 33    }
 34    result, err = doStuffC()
 35    if err != nil {
 36        // Error handling omitted
 37    }
 38    result, err = doStuffD()
 39    if err != nil {
 40        // Error handling omitted
 41    }
 42}
 43{% endhighlight %}
 44
 45Go has good intentions by removing exceptions. They add a lot of overhead and
 46returning errors isn't a bad thing in general. However, I spend a lot of my time
 47writing assembly. Assembly can use similar mechanics, but I'm spoiled by it (I
 48know, spoiled by assembly?) and I can see how Go could have done better. In
 49assembly, `goto` (or instructions like it) are the only means you have of
 50branching. It's not like other languages where it's taboo - you pretty much *have*
 51to use it. Most assembly also makes it fancy and conditional. For example:
 52
 53    goto condition, label
 54
 55This would jump to `label` given that `condition` is met. Like Go, assembly
 56generally doesn't have exceptions or anything similar. In my own personal flavor
 57of assembly, I have my functions return error codes as well.  Here's how it's
 58different, though. Let's look at some code:
 59
 60{% highlight nasm %}
 61call somethingThatMightFail
 62jp nz, errorHandler
 63call somethingThatMightFailB
 64jp nz, errorHandler
 65call somethingThatMightFailC
 66jp nz, errorHandler
 67call somethingThatMightFailD
 68jp nz, errorHandler
 69{% endhighlight %}
 70
 71The difference here is that all functions return errors in the same way - by
 72resetting the Z flag. If that flag is set, we do a quick branch (the `jp`
 73instruction is short for `jump`) to the error handler. It's not clear from looking
 74at this snippet, but the error code is stored in the A register, which the
 75`errorHandler` recognizes as an error code and shows an appropriate message for.
 76We can have one error handler for an entire procedure, and it feels natural.
 77
 78In Go, you have to put an if statement here. Each error caught costs you three
 79lines of code in the middle of your important logic flow. With languages that
 80throw exceptions, you have all the logic in a readable procedure, and some error
 81handling at the end of it all. With Go, you have to throw a bunch of
 823-line-minimum error handlers all over the middle of your procedure.
 83
 84In my examples, you can still return errors like this, but you can do so with a
 85lot less visual clutter. One line of error handling is better than 3 lines, if you
 86ask me. Also, no one gives a damn how you format assembly code, so if you wanted
 87to do something like this you'd be fine:
 88
 89{% highlight nasm %}
 90call somethingThatMightFail
 91  jp nz, errorHandler
 92call somethingThatMightFailB
 93  jp nz, errorHandler
 94call somethingThatMightFailC
 95  jp nz, errorHandler
 96call somethingThatMightFailD
 97  jp nz, errorHandler
 98{% endhighlight %}
 99
100Or something like this:
101
102{% highlight nasm %}
103call somethingThatMightFail  \ jp nz, errorHandler
104call somethingThatMightFailB \ jp nz, errorHandler
105call somethingThatMightFailC \ jp nz, errorHandler
106call somethingThatMightFailD \ jp nz, errorHandler
107{% endhighlight %}
108
109The point is, I think Go's error handling stuff make your code harder to read and
110more tedious to write. The basic idea - return errors instead of throwing them -
111has good intentions. It's just that how they've done it isn't so great.