Why I'm not leaving Python for Go

23 September 2012

First of all, Go seems like a great language. It has an excellent tutorial which I joyfully went through and found: But there's one problem I can't live with. Which is a shame as I was eager to make the leap of faith in the name of concurrency. That problem is errors are handled in return values. 70's style.

Verbose and repetitive error handling

The designers of go consider this a virtue.
In Go, error handling is important. The language's design and conventions encourage you to explicitly check for errors where they occur (as distinct from the convention in other languages of throwing exceptions and sometimes catching them). In some cases this makes Go code verbose, but fortunately there are some techniques you can use to minimize repetitive error handling.
This is one of the things I can't stand in C. Every single line requires an if statement to prevent programs from doing crazy things. This is an official, canonical example from the aforementioned link with perhaps "minimal repetitive error handling":
    if err := datastore.Get(c, key, record); err != nil {
        return &appError{err, "Record not found", 404}
    }
    if err := viewTemplate.Execute(w, record); err != nil {
        return &appError{err, "Can't display record", 500}
    }
The correct way to call a function in Go is to wrap it in an if statement. Even Println returns an error value that I'm sure most on the planet will never check. Which brings me to...

Errors passing silently - ticking time bombs to go

To quote Tim Peters:
Errors should never pass silently Unless explicitly silenced
Go isn't just stuck with verbose and repetitive error handling. It also makes it easy and tempting to ignore errors. In the following program we would trigger the doomsday device even if we failed protecting the presidential staff.
func main() {
    http.Get("http://www.nuke.gov/seal_presidential_bunker")
    http.Get("http://www.nuke.gov/trigger_doomsday_device")
}
What a shame. Oops.
In theory we could require the programmer never ignore returned errors. By static analysis or convention. In practice it'd be a pain worth enduring only in the most error critical programming tasks. Perhaps that's Go's purpose.

panic/recover

Panic and recover aren't good enough as long as the standard library rarely uses them. Why is an array out of bounds any more cause for panic than a bad format string or a broken connection? Go wanted to avoid exceptions entirely but realizing they can't - a few exceptions were tacked on here and there, leaving me confused as to which error happens when.

Perhaps another time

So I say this with much regret because Go has a lot of amazing ideas and features, but without modern error handling - I'm not going. I'm still waiting for that open source, concurrent, bottom left language to come along. Any suggestions are more than welcome.