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:
- Go is Fast.
- Concurrent by design.
- Typed (important for JIT and IDE's) but not cumbersome and ugly like C or C++'s spirals.
- Duck-type-esque interfaces.
- The defer mechanism is really nifty.
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.