Why Go’s design is a disservice to intelligent programmers

Posted on 25th March 2015 by Gary Willoughby

Over the course of the past few months I’ve been using Go to implement a proof of concept program in my spare time. This was done in part to learn Go and to also see if such a program would work. The program itself is very simplistic and not the focus of this article but my experience of using Go is worth writing a few words. Go is shaping up to be a popular language for doing serious large scale work and a language created by Google is not to be sniffed at. With all that said, I honestly think Go’s design is a disservice to intelligent programmers.

Created for lesser programmers?

Go is very easy to learn, in fact it’s so easy it took me one evening to read an introductory text and be productive almost immediately. The book I learned from was entitled An Introduction to Programming in Go and is available on-line. Similar to Go, the book is easy to read with good examples and clocking in at about 150 pages you can finish it in one sitting. Initially this simplicity starts off very refreshing in a programming world full of overly complicated technologies but there’s a niggling thought of "Is that it?".

Google maintains that Go’s simplicity is a selling point and it’s designed that way for maximising productivity in large teams but I’m not convinced. There are aspects of Go that are either seriously lacking or overly verbose because it doesn’t trust developers to get things right. This focus on simplicity was a concious decision made by the language designers and in order to fully understand why, we need to understand the motivation for developing Go and the state of mind of the creators.

So why create it so simple? Well, here’s a few quotes from Rob Pike:

The key point here is our programmers are Googlers, they’re not researchers. They’re typically, fairly young, fresh out of school, probably learned Java, maybe learned C or C++, probably learned Python. They’re not capable of understanding a brilliant language but we want to use them to build good software. So, the language that we give them has to be easy for them to understand and easy to adopt. – Rob Pike 1

It must be familiar, roughly C-like. Programmers working at Google are early in their careers and are most familiar with procedural languages, particularly from the C family. The need to get programmers productive quickly in a new language means that the language cannot be too radical. – Rob Pike 2

What? So Rob Pike is basically saying that the developers at Google aren’t very good so they’ve developed a dumbed down language so they can get things done. What a condescending view on your own employees. I’ve always thought that the developers at Google are hand picked from the brightest and best on Earth. Surely they can handle something a little more complicated?

Artifacts of being too simple

Being simple is a noble pursuit of any design and trying to make something simple is hard. However, when trying to solve (or even express) complicated problems you sometimes need a complicated tool. Of course too much complexity is bad in programming but there is a nice middle ground when the language allows you to create elegant abstractions that make things easier to understand and use. From my experience of using Go it’s just too simple to create useful abstractions.

Not very expressive

Because Go is so simple most constructs that other languages take for granted have been left out. On the surface this looks like a good idea but when confronted with a problem you can only write verbose code. A reason for Go’s simplicity is to help developers read other people’s code but being overly simplistic actually hurts readability. There are no shortcuts in Go, it’s verbose code or nothing.

For example, if you are writing a command line tool that needs to read text input from stdin or a file passed as an argument, you might do it like this:

Although this code is trying to be as generic as possible you are hamstrung by Go’s forced verbosity and a simple task ends up being a lot of code.

Here’s the same example using the D language:

Now, which one is more readable? I’d choose the D version. It’s a lot more readable purely because it’s expressing the program’s intent in a much more clear way. This code also uses concepts that are more advanced than the Go code but they’re nothing too complicated that an intelligent programmer couldn’t pick up quickly and easily.

Boiler plate hell

A feature often requested for Go is support for generics. This would at least allow for stopping all the unnecessary boiler plate code that has to be created to support all needed data types. If for example you’d like to create a function which calculates the sum of a list of integers you are immediately sentenced to implementing the same function for all needed data types. There simply is no other way around it.

Here’s an example:

This example doesn’t even implement all the integer types, just the signed ones. This is a complete violation of DRY, one of programmings most well known and understood principles and ignoring it is a huge source of bugs. Why on Earth would you want to do this? This is a terrible facet of Go.

Here’s the same example in D:

Simple, elegant and straight to the point. Here the reduce function can handle any type and the predicate (passed as a template parameter) defines how to reduce the list. Yes it’s more complicated than Go but not so complicated that intelligent programmers can’t understand it. Which is more maintainable and easy to read?

An easily circumvented type system

I guess by now Go programmers reading this will be frothing at the mouth shouting “You’re doing it wrong!”. Well, there is another way of implementing generic functions and data types, and that is to completely break the type system!

Check this example out for a showcase of stupidity patching a language to overcome shortfalls:

This Reduce implementation was taken from an on-line article entitled Idiomatic generics in Go. Well if that’s idiomatic, i’d hate to see un-idiomatic. Using interface{} is a farce and is only included in the language to circumvent type checking. It is an empty interface which is implicitly implemented by all types allowing a total free for all. This style of programming is as ugly as hell and not only that but to perform such acrobatics in the above example you are also forced to use runtime reflection. Even Rob Pike doesn’t like people abusing reflection and has mentioned this in many talks.

It’s a powerful tool that should be used with care and avoided unless strictly necessary. – Rob Pike 3

I’d take D’s templates any day over this nonsense. How can anyone say interface{} is more readable or even type safe?

Dependency management woes

Go has a built-in dependency system which is built upon popular source control hosting services. The tools that ship with Go are aware of these services and can retrieve code from them, install and build it in one fell swoop. While this is great, there is a major oversight and that is versioning! Yes that’s right you can retrieve source code from services such as github or bitbucket using the Go tools but you can’t specify a version of the code. Again this screams that the design has been made as simple as possible to the detriment of being useful. I can’t fathom the thinking behind such a decision.

When questions where asked about this state the Go team wrote a forum thread outlining how they where going to get around this issue. Their recommendation was to just copy the entire repository at that time into your project and leave it as-is. What the hell are they thinking? We have these awesome source control systems with great tagging and version support which the Go creators ignore and just copy the whole thing around.

Cultural baggage from C

In my opinion Go has been designed by people who have been using C all their lives and don’t want to try anything new. The language could be described as C with training wheels. There is no new ideas in the language apart from the concurrency support (which is excellent by the way) and it’s such a shame. You have this great concurrency support in a barely usable, hamstrung language.

Another grating issue is that because Go is procedural (just like C ‘shock horror’) you start writing code in a procedural way which feels archaic and old hat. I know object-oriented programming is no silver bullet but it would have been nice to be able to abstract details away into types and provide better encapsulation.

Simplicity for its own sake

Go was designed to be simple and it has succeeded in that goal. It has been written for lesser programmers using an old language as a template. It comes complete with simple tools for doing simple things. It is simple to learn and simple to use.

It’s overly verbose, inexpressive and a disservice to intelligent programmers everywhere.