My thoughts on Go (again)
A little over three years ago I blogged my thoughts on the Go programming language. At the time I said Python > Scala > Go. I came to that conclusion by reading all of the various docs available on the Go website and then doing a couple of toy examples. But since I did that evaluation I have shifted from a breadth-based evaluation of various programming languages to a more depth-based one (mainly due to a lack of time and thus having to be picky about what programming languages I learn). I’m also evaluating languages for a website that I have been planning to build for years which will have both a front-end and back-end component. That means choosing two languages for the project. For the moment I’m focusing on the back-end language.
Since I’m going to be doing this project with a good friend of mine I’m not instantly choosing Python as the back-end language. While Python would let me be the most productive, a personal programming project should be fun, useful in a utilitarian sense, and a learning experience. While doing Python web back-end stuff would of course lead to some learning, it wouldn’t be nearly as much of a learning experience if I did the project in a different language. Plus using Python might not be as useful professionally for my friend as other languages.
But what language we choose can’t suck. =) While being an admitted programming language polyglot/whore, I am also willing to admit I'm an opinionated/biased polyglot/whore. That means I'm not going to use just any language since I would like to think I know good language design is and thus can’t stand poorly designed languages (just ask my co-workers).
And so I am evaluating Go and Scala as potential back-end languages for this project. Both are somewhat niche compared to e.g. Java, but they are gaining users consistently. Both are being used at real world companies which scale to large user bases. Both languages are high level and so I don't have to care about things like memory management or pointer fiddling. Both languages are stable and passed their 1.0 releases. But most importantly, both languages don’t drive me bat-shit crazy.
For Scala I have been taking the “Functional Programming Principles in Scala” course at Coursera to refresh my functional programming chops as well as Scala knowledge (plus another friend of mine said she would learn Python if I took the course, so there’s that =). But for Go I didn’t have an equivalent (I took A Tour of Go previously, but it doesn’t teach me a programming paradigm I rarely get to use).
Luckily a little coding project popped up for me that Go seemed suited for: I needed to find out what files were duplicates of each other. While not complicated or requiring any novel programming solution, that’s actually not a bad thing when evaluating a language. It means that for the mundane stuff you can see if the language functions in a way that makes sense to you and allows you to be productive. And productivity is important. For one this is a personal project so I don’t want or need it to scale to a Google service so I don’t need to consider sacrificing my time in the name of efficiency (e.g. I ain’t going to use C++ to try and eek out every cycle of performance). I also have a limited amount of free time so I don’t want to sacrifice more time than I have to (within reason, obviously, else I would just use Python).
Anyway, I ended up coding a solution over a couple of nights when I had a few spare minutes that totals a little over 200 lines. That includes both a synchronous and partially concurrent solution. There is slightly less than that number of lines of testing code as well. So nothing that complicated, but it did involve all the basics and allowed me to get more of a feel of the language and a refresh of what I already knew from three years ago.
What conclusions about Go did I draw? You can tell the language was designed by systems programmers who wanted to be more productive (which makes sense if you know Go’s history). From the support of passing objects by pointer to the lack of exceptions, it’s obvious Go team members come from a history steeped in C++ coding (at Google especially) where they grew tired of manually managing memory and such but didn't want to entirely want to toss out all of the practices found in C/C++. And that’s totally understandable since you don’t necessarily want to fully diverge from common practices of your target audience, else you risk not gaining users.
And yet, somewhat ironically, it isn’t the C/C++ programmers that have taken to Go but the Python/Ruby programmers. Why is that? Well, when I have watched presentations on Go and there is a die-hard C++ programmer in the audience who asks a question, it typically revolves around how to gain back some control that Go has taken away, e.g. turning off garbage collection or more pointer control. In other words the typical programmer who loves C++ doesn't want to give up any control, while Go’s entire point is to take some of that control away to try and make you more productive.
Dynamic programming language lovers, though, are used to giving up plenty of low-level control for productivity gains. And so when a language like Go comes along that is small enough to fit in your head and gives you great performance characteristics you don't mind that you are giving up some high-level constructs for low-level speed boosts. That’s why some Python/Ruby programmers are switching. It does paint Go in a different light if you take it as Python but with typing and certain performance-hurting aspects removed compared to C++ but with abilities removed to make your life simpler.
Personally, I don't buy into the trade-off wholesale. I would have to measure performance against using PyPy in a project before I started tossing Python aside entirely and losing it’s flexibility in the name of speed. I do see the appeal though. Nothing really jumped out at me as horribly designed or a something that would totally drive me bonkers. Probably the biggest stumbling block was coming up with some idiomatic way to have a pool of goroutines to handle the hashing of files. After that it was realizing defer
calls are executing at function exit and not code block exit (RAII in C++ and context managers in Python spoil you). Otherwise nothing leapt out at me to cause me to want to drop the project.
In the end, Go is still a viable language to use. Yes, it requires a bit more work than Python to reach the same semantic conclusion, but it isn't enough to drive me up the wall. And the trade-offs it asks of me to write maintainable, fast code do not feel systematically unreasonable. If someone wouldn't let me use Python for a project I would present Go as an alternative.
Now I just need to see how more Scala stacks up with some other test project to see which language I prefer behind Python.