On Rob Pike and Go

Rob Pike (co-author of Go) said:

OOP languages frequently shift the focus from data structures and algorithms to types.

I haven’t tried Go yet, but this resonated with me as a Clojurist. Managing all your state as classes and objects almost always, instead of just designing some nice mix of data structure for it. And then writing all your functions as methods restricted only to the data on that object, gets in the way of coming up with wholistic algorithms over data structures.

He also said:

If C++ and Java are about type hierarchies and the taxonomy of types, Go is about composition. […] It is a language of composition and coupling. The obvious example is the way interfaces give us the composition of components. It doesn’t matter what that thing is, if it implements method M I can just drop it in here.

Which as a Clojurist also resonated with me. Apparently (correct me if I’m wrong), in Go, interfaces are implicits and match only by name, not by type. In effect, this sounds a lot like what a dynamic type system gives us with regards to polymorphism. Who cares, if the thing fits at run-time I’ll use it. And that idea of composition just by functions and only based on their name, it’s very much something I agree with and one of the things I like about Clojure.

He said as well:

Another important example is how concurrency gives us the composition of independently executing computations

Go has CSP, like Clojure core.async. So this obviously resonates with me as well. But especially the broader idea here, that concurrency is about composition of independently executing computations. Clojure brings other concurrency controls, like immutability being the main one, and I think a good aspect to consider is how would you compose code running concurrently or in parallel? Having things be immutable help, CSP helps, agents help, refs help, atoms help, etc. It’s all about composition, I like that.

And another thing he said:

Programmers who come to Go from C++ and Java miss the idea of programming with types, particularly inheritance and subclassing and all that. Perhaps I’m a philistine about types but I’ve never found that model particularly expressive. […] Type hierarchies are just taxonomy. You need to decide what piece goes in what box, every type’s parent, whether A inherits from B or B from A. Is a sortable array an array that sorts or a sorter represented by an array? If you believe that types address all design issues you must make that decision. […] I believe that’s a preposterous way to think about programming. What matters isn’t the ancestor relations between things but what they can do for you.

This also resonated with me. In fact, I think it’s one challenge for people coming to Clojure sometimes, they miss this “type driven development”. And kind of don’t know how else to design their code.

He finishes by saying:

If C++ and Java are about type hierarchies and the taxonomy of types, Go is about composition. […] What you’re given is a set of powerful but easy to understand, easy to use building blocks from which you can assemble—compose—a solution to your problem. It might not end up quite as fast or as sophisticated or as ideologically motivated as the solution you’d write in some of those other languages, but it’ll almost certainly be easier to write, easier to read, easier to understand, easier to maintain, and maybe safer.

Now I feel you could literally replace Go with Clojure here and it be just as applicable.

All this is from: https://commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html?m=1

I found it quite interesting, and actually was surprised at how much similarity in the philosophy of Go it seems Clojure shares. Now there are some other things in the article I don’t resonate as strongly or would slightly disagree with, but to some extent those seem to be more about the best way to create a language that applies these philosophies and ideas I just quoted. For example, I’d rather everything be an expression, I’d favor functional programming over procedural, and I’d want a Lisp syntax and power to extend the language semantics of my own with macros.

Anyway, I recommend it for reading, and am interested in hearing other people’s thought on this.

3 Likes

It feels (a bit) like he’s focusing on the negative aspects instead of the positive ideas, which are partially available in Golang. Object orientation, as Alan Kay would be happy to tell you, is not about taxonomies, but about polymorphism, message passing, and late bindings.
You can achieve polymorphism by subtyping, but Clojure is a good example of two open polymorphism systems - multimethods and protocols, neither of which use subtyping.

So how do we start from these wonderful principles and end up with Golang on one hand and Clojure on the other? I think the discussion is incomplete without the following quotes:

The key point here is our programmers are Googlers, they’re not researchers. They’re typically, fairly young, fresh out of school, probably learned Java, maybe learned C or C++, probably learned Python. They’re not capable of understanding a brilliant language but we want to use them to build good software. So, the language that we give them has to be easy for them to understand and easy to adopt. – Rob Pike

It must be familiar, roughly C-like. Programmers working at Google are early in their careers and are most familiar with procedural languages, particularly from the C family. The need to get programmers productive quickly in a new language means that the language cannot be too radical. – Rob Pike

Clojure, on the other hand, was designed for experienced programmers.
I think these differences show, and are easy to feel when you program with Golang (I took it for one or two rounds around the block). It’s extremely verbose, very straightforward (more along the one-way-to-do-things school of thought), and feels like it holds your hand a lot. Like it was designed to produce code by quantity, and not quality.

Besides, it has a few odd design choices which impact any work you want to do with it:

  • no generics (this horse was beat to death)
  • goroutines return no value and can’t be synchronized elegantly. This post did a lot to influence the design of Project Loom
  • mysterious gotchas: Go has supposedly great performance. Unless you escape to heap, or if your initial goroutine stack isn’t large enough. Which are things novice programmers will get wrong.

While some of the initial design considerations might have been similar, I must say my experience with Go was meh/10. It works, it does its job well, and I’d rather write in a Lisp. With the new features coming into Java, I’d prefer that, as well.

Edit/Addendum: I must say though, the work the Go team has done on the compiler and assembler is inspired and amazing and everyone should learn from it.

6 Likes

I try to follow the Pragmatic Programmer advice and learn a new language every year (or two-ish, more accurately for me). Go is one of several languages I’ve learned over the last decade. My opinion of it is, I suspect, much like @bsless’s: it does what it is designed to do but it’s kind of “meh”. After hearing all the hype about it, I had hoped to really like it, or at least enjoy programming in it. I found it ugly and tiresome to work with, to be honest.

Since then, I learned Rust – and it was much more what I had hoped Go would be like. I won’t say I enjoyed programming in Rust (the borrow checker is so finicky!) but as a language, I like it a lot more than Go.

I have a long history with C++ (about a decade of production work, and eight years on the ANSI C++ Standards Committee) and I would rather use C++ than Go, to be honest, but I think I would rather use Rust than C++.

Languages are subjective choices on many levels: I have friends who absolutely adore Go and I won’t criticize them for liking it.

7 Likes

I learned Go for a small task at work a couple of years ago and had similar feelings about writing it. However I think it may be the easiest mainstream language to read - it really was a pleasure when learning to find I could almost immediately dive into huge open source codebases and see pretty clearly what was going on.

Rust I had a decent crack at for interest but never ended up writing enough of it to feel fluent. It has all kinds of interesting ideas in it (I enjoyed reading about it more than writing it), but tended to feel more like a disparate bag of tools rather than a single principled system. The iterators and combinators for example felt like a kind of embedded language and required a different manner of thinking from the surrounding code.

Even though I was unconvinced by the result, I preferred the principle underlying Go’s design - a tight set of orthogonal constructs which combine to do everything you need - to Rust’s more Baroque approach. But I think you’re right @seancorfield, much if not most of this is a matter of personal fit.

Good catch, that’s a really funny and kind of condescending snippet here. You’d think Google would proud itself about how talented and smart their hires are, considering how stringent their hiring process is. Yet somehow, it doesn’t believe them capable enough to understand a brilliant language :joy:

As for Go itself, I’m the kind of programmer who enjoy being given free reign to shoot myself in the foot or figure out my own preferred way to do anything. That’s why I haven’t tried Go yet, cause I feel like I know it explicitly doesn’t give me that.

That said, ya, like @bsless says, I thought it was really interesting that similar philosophies in a lot of ways arrive us two completely different places.

I also feel though like there could be a Go like lang, that just adds a little bit more freedom, like if it used a Lisp syntax and had macros for example :stuck_out_tongue: And it would seem pretty good. Well, okay, I’d also want it to be more functional, and default.to be immutable, and then I’d just get something like Clojure again haha. But still, Go with Lisp syntax and macros on its own feels like it would address most of what people complain about, which is mostly the verbosity.

One of the biggest problems of writing a compiled lisp in Go is that incremental compilation and dynamic loading of code are not really an option, so you either lose the REPL or lose performance. Generics will take you a bit closer in terms of performance, but only just.
If you haven’t yet, take a look at joker

1 Like

I had a good chuckle from that too. :wink:

1 Like

Sean, as you mentioned Pragmatic Programers book, one of the authors, Dave Thomas is very engaged with Elixir, so this is OFF-TOPIC, but it’d be nice to know your impression about Elixir.

I haven’t looked at Elixir because I understand the syntax is basically Ruby? And I really don’t like Ruby (I was a community teaching assistant on the Washington University “Programming Languages” course for several years and it uses Ruby as one of the three teaching languages – the others are Standard ML and Racket).

1 Like

Elixir resembles Ruby only on surface,

It’s the surface (syntax) of Ruby that I particularly do not like :slight_smile:

If I want to do anything on BEAM (I don’t), then I would use Erlang as I’m perfectly happy with that syntax, which is inspired by (Edinburgh) Prolog which I like using. Or perhaps I would use LFE so I could write Erlang in a Lisp flavor.

Note: I tend to be very opinionated about languages because I have a background in programming language design and compiler implementation (which is also why I was on the C++ committee for eight years). I’ve used a lot of languages over the last 35 years!

4 Likes

Just read this today as well: https://research.swtch.com/vgo-principles

Seems the Go designer have watched the Spec-ulation talk when it comes to breakage and dependencies as well:

don’t remove exported names, encourage tagged composite literals, and so on. If different functionality is required, add a new name instead of changing an old one. If a complete break is required, create a new package with a new import path

What does compatibility have to do with versioning? It’s important to think about compatibility because the most popular approach to versioning today—semantic versioning—instead encourages incompatibility . That is, semantic versioning has the unfortunate effect of making incompatible changes seem easy.

But then what do we do about semantic versioning? If we still want to use semantic versioning, as many users expect, then the import compatibility rule requires that different semantic major versions, which by definition have no compatibility relationship, must use different import paths

I’m just more and more surprised how much in common philosophicaly there is with Clojure.

In actually curious about repeatability:

Minimal version selection provides repeatability, for whole programs and for libraries, always, without any lock files. It removes time from consideration. Every chosen version is always one of the versions mentioned explicitly by some package already chosen for the build

I know if there are version conflicts, tools.deps picks the latest version. Some old that make it similar in effect to what Go does?

1 Like

You say “Seems the Go designer have watched the Spec-ulation talk when it comes to breakage and dependencies as well”, and then give a quote from the article you link. The first paragraph you quote from the article, beginning with “don’t remove exported names”, is preceded by this sentence: “The Go FAQ has encouraged compatibility since Go 1.2 in November 2013”.

If true, then since Rich’s Spec-ulation talk was in December 2016, then the Go 1.2 FAQ precedes that talk by 3 years.

I don’t know who came up with these ideas first in software engineering, but it definitely looks incorrect to say that Go designers got the ideas by watching Rich Hickey.

3 Likes

reading this made me chuckle a little, because it reminded me of the following:

which reminded me of a famous quote from the aforementioned Alfred North Whitehead:

The safest general characterization of the European philosophical tradition is that it consists of a series of footnotes to Plato.

so, when i am reading:

it would seam to me that, yes, the suggestion would appear to be incorrect, but more importantly the suggestion would also seam to lead one into very tedious disputes about who said what first, who read whom when, who acknowledges to have been influenced by whom in what way and to what extend, etc. :slight_smile:

now,… i am not saying that to give credit where credit is due isn’t important,… but i do think that very often it is much more important what one makes ( out ) of an idea, rather than the idea itself. :wink: