Thoughts on Go vs. Rust vs. Zig
I realized recently that rather than using “the right tool for the job” I’ve been using the tool at the job and that’s mostly determined the programming languages I know. So over the last couple months I’ve put a lot of time into experimenting with languages I don’t get to use at work. My goal hasn’t been proficiency; I’m more interested in forming an opinion on what each language is good for.
Programming languages differ along so many axes that it can be hard to compare them without defaulting to the obviously true but 1) entirely boring and 2) not-that-helpful conclusion that there are trade-offs. Of course there are trade-offs. The important question is, why did this language commit to this particular set of trade-offs?
That question is interesting to me because I don’t want to choose a language based on a list of features as if I were buying a humidifier. I care about building software and I care about my tools. In making the trade-offs they make, languages express a set of values. I’d like to find out which values resonate with me.
That question is also useful in clarifying the difference between languages that, at the end of the day, have feature sets that significantly overlap. If the number of questions online about “Go vs. Rust” or “Rust vs. Zig” is a reliable metric, people are confused. It’s hard to remember, say, that language X is better for writing web services because it has features a, b, and c whereas language Y only has features a and b. Easier, I think, to remember that language X is better for writing web services because language Y was designed by someone who hates the internet (let’s imagine) and believes we should unplug the whole thing.
I’ve collected here my impressions of the three languages I’ve experimented with lately: Go, Rust, and Zig. I’ve tried to synthesize my experience with each language into a sweeping verdict on what that language values and how well it executes on those values. This might be reductive, but, like, crystallizing a set of reductive prejudices is sort of what I’m trying to do here.
Go
Go is distinguished by its minimalism. It has been described as “a modern C.” Go isn’t like C, because it is garbage-collected and has a real run-time, but it is like C in that you can fit the whole language in your head.
You can fit the whole language in your head because Go has so few features. For a long time, Go was notorious for not having generics. That was finally changed in Go 1.18, but that was only after 12 years of people begging for generics to be added to the language. Other features common in modern languages, like tagged unions or syntactic sugar for error-handling, have not been added to Go.
It seems the Go development team has a high bar for adding features to the language. The end result is a language that forces you to write a lot of boilerplate code to implement logic that could be more succinctly expressed in another language. But the result is also a language that is stable over time and easy to read.
... continue reading