In case you are wondering, the title of this post is a nod to Brian Kernighan’s Why Pascal isn’t my favourite programming language. I’m only showing my age here, not trying to compare myself to Kernighan 🙂
There has been a lot of buzz recently about the Go programming language. There was an article on Slashdot recently, videos of Google talks on YouTube (slides), the works. And of course, there is the Go web site itself. The YouTube video below has been viewed 183,000 times as of this writing, so the roll-out campaign had some success…
Of particular interest are the minds and forces behind the language. The initial contributors are Robert Griesemer, Ken Thompson, and Rob Pike, and the project was developed at Google over a time period of two years. With such a pedigree, expectations are high. And that’s probably why I’m a little disappointed with what was presented so far. It’s not that it’s a bad language, it’s more like as so-what language. There’s nothing I find really compelling about it. In particular, I didn’t find anything that would make me significantly revisit my own pet programming language, XL.
The point of views below are indeed largely based on my own experience designing and implementing a programming language. So I would say that they are both educated and biased. Keep this in mind as you read on. Also, I tend to point out the negative aspects because the campaign discussed above did a rather good job at highlighting the strong points of Go.
My initial impression of the Go programming language, based on the material above, is that it has a few serious flaws:
- No generics: Go is yet another language where generics will be bolted-on as an afterthought. As a direct consequence, Go includes many constructs (including maps or goroutines) that in my opinion rightfully belong to a library. This is important for programmers: the choices of the Go designers might not match the needs of the Go programmers. Worse yet, if you have some reason to use some kind of fancy container, Go is not the right language to implement it.
- Not suitable for what I call “Systems”: The Go designers seem to consider that “Systems” equates writing applications such as web browsers. To me, “systems” implies that you can write programs that may talk directly to the hardware (as in operating systems or real-time systems). At first glance, Go seems ill-suited for such tasks. In particular, it does not just provides a concurrency or memory management model, but actively enforces it at the language level. In other words, if you want to write a real-time system in Go, you first need to implement the runtime support for goroutines or Go garbage collection. I ran into this problem in the early days of HPVM: implementing a C++ runtime on bare metal proved complicated enough that I had to rewrite my C++ binary translator in plain old C.
- Orwellian Newspeak: The two examples above illustrate how, all too often, Go “knows what is good for you” and won’t let you deviate from the party line. This goes as far as imposing where the braces go for rather bogus syntactic reasons, deciding when you can use upper-case letters, or formatting the code automatically when you submit it!
These three aspects of the design mean that I probably won’t use the language seriously any time soon. I can’t do meta-programming well because of the first issue. I can’t do system software because of the second issue. And if I want to explore, I will be constrained in what I can do because of the third one. These issues may not mean as much to the majority of programmers, though. Just because Go is not a language for me doesn’t mean that it won’t work for you. Your mileage may vary.
In any case, there are a number of aspects to the Go language worth discussing, if only because of the publicity it received.
The objectives of the team in creating the language are, according to the slides:
In my humble opinion, these objectives lack a clear sense of direction and purpose. They include mere facts (“New”), low-level implementation details (“Garbage-collected”), usage models (“Systems”) and actual design objectives (“Concurrent” and maybe “Experimental”). Specifically, “New” might be intended to mean innovative, but while there’s little debate that Go is new, I didn’t find much in it that wasn’t already hammered elsewhere. “Experimental” should probably mean that it explores a few radical ideas, but it could also simply reveal that it’s not fully cooked yet. Unfortunately, radical ideas are exactly what I didn’t find.
Concurrency is the most interesting of these objectives. It is not exactly a novel idea, but there is still a lot of progress to be made in how languages support concurrency. Still, it’s hard for me to see what Go adds compared to industrial languages like Erlang. Sure, Rob Pike demonstrated 100,000 goroutines completing in 1s. At first sight, that might seem impressive. But according to this source, someone ran 20 million processes in Erlang as early as 2005. And apparently, run-time performance at the time were similar: 5.3μs + 6.3μs times 100,000 would be 1.16 second, very comparable to what Rob Pike demonstrated on presumably faster hardware.
The language prominently features garbage collection. Garbage collection for memory today is practically a given. You can’t appeal to Java programmers without it. But collecting garbage is not about just memory objects. In real programs, there are many other forms of garbage to recycle: temporary files, open files, locks, threads, open network connections, … Furthermore, the requirements placed on the garbage collector may vary from application to application. Providing a garbage collector by default is good, providing one that is implemented in the library, that you can taylor to your needs and [gasp] apply to non-memory objects would be so much better… In short, is Go’s garbage collection worth the prominent position that its designers gave to it in the presentations? I don’t think so personally.
It’s even more interesting to analyze the implicit objectives of the language. I could find at least three such objectives that, while not explicitly stated, seemed quite important to the design team.
- Compilation speed: There were many demos of how fast Go compiles, and it’s featured prominently on the front page of the web site, so this seems to be a rather important objective to the Go design team.
- Simplicity: Although it is being described as “slightly bigger than C”, Go is clearly intended to remain simple, with a simplified syntax, no parsing ambiguities, …
- Programmer comfort: Rob Pike stressed how the language is designed to make it easy to write tools, to compose software (there’s a rather nice dependency checking mechanism), to reduce typing, and so on. And of course, not waiting for the compiler is comfortable too.
All these are rather noble objectives. But they also stress the kind of trade-offs that were made in the design of the language. For example, compilation speed does matter, nobody can dispute that. But in exchange for that speed, we pay 10% in execution speed, and more importantly we lose a number of features I consider essential for productivity, like templates. This may not matter much to software consumers, however. It is true that more and more, we simply compile someone else’s code. In that case, compilation speed is practically the only metric that matters.
Tipping the balance the other way, why not push the reasoning to the limit, and ditch compilation entirely? A lot of recent work has been in the field of just-in-time compilers. LLVM has shown that it’s possible to dynamically generate high-quality code in a portable way. The XLR runtime component of XL is now using LLVM, so that you can execute XLR programs (that is, the run-time language) without any explicit compilation. Compilation does happen, but entirely transparently, on the fly, as you execute the program. In that scenario, some heavier compilation remains possible once the program runs, to get better optimizations, faster execution or tighter verification of the code.
In conclusion, Go shows how difficult it is to design an innovative programming language for today’s programming world. Many of the choices made by the design team seem rather old-fashioned to me. Go didn’t rattle my brain the way Haskell, Erlang or Ada did in their time.
But ultimately, the bottom line for me is this: Go seems to be a solution in search of a problem.