C vs Go: Opinionated Design in Programming Languages

The C programming language and the Go programming languages are my all-time favorite tools for programming. Full stop. These two languages are so versatile, so extensible and so incredibly useful that I have yet to come across a problem in which neither of the two is appropriate for use. And yet, these two languages are, evidently from even the slightest bit of use, radically different in their approaches to programming language design. Having sat down and had a serious think about the subject, I have finally come to a conclusion about what this fundamental difference is.

You see, C is designed with what I call “Design Indifference”. Effectively, the philosophy of the language is that the language will have no opinion on how the user organises their code. It shall not enforce any rules on how code ought to be written, nor shal it restrict the user from using certain features of the machine because the author thought that that feature is not safe or necessary for well written programs. Whatever is technically possible, C shall allow you to do.

Go, however, is a very opinionated language. Essentially, the designers of Go (possibly the most prominent of which is Rob Pike) had strong opinions on what should and should not be present in the language. In a 2015 talk, Rob Pike said that he and the rest of the Go designers would all have to unanimously agree on the inclusion of a feature into the language before it would be added. This made the Go language substantially higher level than the C language, but also very minimal. However, this also is where the opinionated nature of Go’s design comes from. The opinions of all these people were taken into account, not just what the machine is capable of doing being allowed.

There is no more a perfect example of this than Go pointer arithmetic. It is stated very clearly in The Go Programming Language (2015) that Go intentionally does not include pointer arithmetic, being a feature which is purposefully absent when compared to C. In C, it is recognised that a pointer is simply an integer like anything else stored in registers, and therefore can be manipulated like anything else. This means that C will, like it does with anything else, allow you to do arithmetic on it. What you use this for is your decision. You can use it as a more convenient (and efficient) way of getting a pointer to an array element. You can (technically, although I really don’t recommend this) use it to get at adjacent elements in structs). The point being, the language doesn’t care about why you may wish to do this: it is possible for the machine to do, and so you can do it. Go, however, does not have this attitude. Instead, if the designers of the Go language see no reason for you to do something, you can’t do it. Simple as.

Another good example is variable naming schemes. There is no way to export a variable or function from a package in Go without making the naming of said exported symbol upper-case. The upper-case nature of this symbol is what denotes it as exported. The Go designers do not care that some people may wish to write this another way and export it manually. This is the way Go is invisioned - deal with it.

Now, I do not have a particular preference either way as to which design is better or worse. I have written fairly important C applications and written some rather important Go applications. Both of these sets of projects use the languages to their fullest extent as needed. Both of these were joys to write.

At the end of the day, there is nothing wrong with writing an opinionated programming language, so long as you have good justification for your opinion on code and software development - and so long as people can widely accept this opinion and work well with it. And there is similarly nothing wrong with creating a programming language which is just a simple tool which does as you say. Some people won’t like Go because of its opinion on these matters. Others, like myself, may share this opinion. And, other may just take on this opinion because they trust in the genius of Rob Pike and Ken Thompson. But either way, C and Go are very good examples of near-perfect executions of both models.

Ethan Marshall

A programmer who, to preserve his sanity, took refuge in electrical engineering. What an idiot.


First Published 2021-08-10

Categories: [ Old Blog ]