Is Go too simple? Or still too complicated?

For some people, Go has a severe lack of "features", while for others, it should even be simpler. Where does Go really stand?

A new language arrives

In the year 2007, Robert Griesemer, Rob Pike, and Ken Thompson attended a C++ conference at which a truckload of new language features was announced, despite the fact that the C++ language specification already was complex enough to fill several hundred pages. So not much later, they decided to design a new language where one of the primary features is the absence of many features. And this included many features that, up to this point in time, many people had considered fundamental features of modern programming languages.

Gosh, this language is too simple to be taken seriously!

Not surprisingly, when Go 1.0 arrived in 2011, many people were skeptical about the language. To them, Go's promise of being an easy-to-read language implied that it could not be in any way sufficient for "real-world", large-scale programming. Because, in their eyes, ignoring such "invaluable" features like classes, inheritance, operator overloading, function overloading, option types, union types, etc. etc. can only mean that this funny language must be insufficient for any complex project.

Wait, what happens in my code?

It did not take long, however, until blog posts were seen that complained about the exact opposite. These posts focused on aspects where Go seems to be too complicated to be considered an easy language. (One of the first, and maybe the most prominent of these posts, is 50 Shades of Go: Traps, Gotchas, and Common Mistakes for New Golang Devs.) And indeed, Go does have a couple of "gotchas" that, on a first glance, might add to the learning curve. (See the linked article for some examples, but don't dwell for too long there. I know this article can absorb you and you won't be able to stop until you have read through it and tried at least half of the code examples.)

The point is, a language of sufficient expressiveness cannot avoid having some rough edges, and Go definitely has some. (But then, if learning the language from a good resource, those rough edges should become obvious and easy to avoid.)

Simple but not too simple

So what's the deal? Is Go too simple or too complicated?

To answer this, we have to look at both sides. Let's look at simplicity first. The question is, what if Go was much simpler than it is already?

Now there are two flavors of "simple": Simple as in "minimalist", and simple as in "convenient".

Moving down the minimalist road would not get us far. At the end of this road we'll find Assembler code, Turing machines, or Brainf**k. Languages with the bare minimum of features needed to get a CPU do something, but far from turing high-level concepts into code efficiently.

So if we remove more and more features from a language,

  • the language will become less expressive
  • more and more lines of code will be required to achieve a given goal
  • the resulting code would be too low-level to clearly show what it accomplishes at the domain level
  • coding would mean micro-managing boring and error-prone details like manual memory management.

Clearly, a minimalist language is not what we want.

But what about convenience? How about a simple but super powerful language that hides all complexity inside the compiler?

In fact, this has been attempted already, and the attempts continue. From Prolog to Workflow machines to Low-Code platforms, there are many approaches that try to remove the "how" from the equation and let the human app designer focus on the "what".

This kind of simplicity also has its drawbacks, including

  • slow and complex compilers
  • slow and inefficient execution
  • debugging becomes difficult as the system makes a lot of decisions under the hood

Neither of these aspects is what I would want to see in a language like Go.

But even if we only try to introduce slight convenience features to make thinks simpler on the surface, we might end up with the opposite - that is, more complexity behind the scenes.

For example, consider a simple convenience feature like automatic conversion between numeric types. This would remove the need of having explicit conversion operators, and source code would look cleaner than when cluttered with conversion operators. However, this would not only complicate the compiler but also add some general confusion) about the exact semantics to expect.

Bottom line - simplifying the language further would not take us to where we want to be. A language made for tackling industry-grade problems needs a good dose of complexity and expressiveness.

Expressive enough but not complicated

Now let's look at the other end of the range. What would happen if the Go team decided to get on a spree of adding more and more features, turning Go into an "all under one roof" supermarket kind of language?

Most certainly, Go code would

  • be harder to decipher
  • be slower to compile, maybe also slower at runtime
  • make code maintenance more difficult
  • be harder to debug
  • be harder to reason about
  • be prone to subtle interference between language features, thus requiring extra rules for proper coding (do's and dont's)

And the language as a whole would

  • be slower and harder to learn and master
  • allow many different ways of doing the same thing, thus hampering readability, especially in teams

I can tell this with a high level of certainty because we already have languages around that suffer from exactly these issues.

Or, as /u/jerf says in this comment on Reddit:

As someone who has to deal with a lot of other people's code as my day job (...), one of the reasons I favor Go professionally is precisely that it prevents people from going crazy with their code and creating a dense clump of immiscible code in some super-local paradigm mix that composes poorly with all the other bits of code.

There is a reason that one of the Go Proverbs says: "Clear is better than clever."

Conclusion

Go represents a good balance between available features, expressiveness, and simplicity. I would go as far as saying,

Go occupies a sweet spot between too simple and too complex.

In many regards, Go goes out of the way and allows developers to focus on the task at hand rather than fighting against complex language mechanisms or struggling to understand other people's code that uses that one obscure language feature from page 739 of the language spec that you heard about on a dev conference a few years ago but never bothered to wrap your brains around.

Go is indeed an ideal team language. Go is basically non-magical, which means that you can look at a piece of code and tell what it does. Go is simple enough to prevent "clever" coding tricks that save a few lines but make the code utterly incomprehensible, and at the same time, Go is expressive enough to boost developer productivity. On top of this, Go delivers fast compilation and high speed at runtime.

Finding all these aspects in a single language is rare. Go is one of the few languages that really deserves the label "pragmatic".

---

Applied Go Courses helps you getting up to speed with Go without friction. Our flagship product, Master Go, is an online course with concise and intuitive lectures and many practices and exercises. Rich graphic visualizations make complex topics easy to understand and remember. Lectures are short and numerous, to help planning and saving your precious time, as well as serving as quick reference material after the course. Learn more at https://appliedgo.com.

Categories: The Language