Discussing Go idiosyncrasies (split thread)

Tags: #<Tag:0x00007f1142c88868>


EDIT Backward reference: Why There is no FP Language Fast As C++

I think that Rusts initial compiler is written in OCaml, can also be part of that list.


Holy sh*t, will it ever happen that I find a language which I love and you wont destroy it for no reason? :smiley:

First of: While I see your skills, I think you underestimate .Net and Java, simply because plain numbers show they can compete

OCaml is surely a blazing fast language, while Java and F# are at least so fast. Yeah, that might change once MCOCaml is merged, while you obviously consider the current OCaml speed as very fast and this is where these languages perform also:


I also think you might consider that there are implementation details in these platforms, which you overlocked

Do you really consider the main developers of .Net and JVM do such obvious mistakes?

Go is superb for newbies, even I as someone who jumps on trees when imperative code comes up, can sometimes reason about it :wink:

It is by far the most readable imperative language yet to me, even easier as Python and it provides such great goods, as easy deployment (come on, one command and you get your binary on all platforms for all platforms and all this without any build scripts and dependencies - how can you ignore this?)

Then, the way how Go handles errors is super interesting and also its pure performance and the network orientation and so on and so on.

How is that garbage?

Is it because you feel the language is too small?

Why There is no FP Language Fast As C++

Can you elaborate please? I find it annoying at best, horrible at worst and it’s one of main reasons why I’m simply dismissing go at this point, that’s why I’m always eager to get others opinions.


So how would you counter these (obviously biased) concerns?

Go is superb for newbies, even I as someone who jumps on trees when imperative code comes up, can sometimes reason about it :wink:

I’m really trying hard to understand the enthusiasm that some people are showing for Go. After going through A Tour of Go I would describe it as tedious - though granted that’s after a fairly short exposure. I get why Google likes it especially if their culture still reflects this attitude from seven years ago.

Maybe being enthusiastic about Go is a matter of perspective. Maybe Go looks pleasant/refreshing enough if your first programming course was in Python and you just pushed through Java with it’s (mostly) OO dogma?

Though I find it (more than) a little annoying when people gas on about Go’s simplicity - all I’m seeing is people being enamoured with familiarity rather than simplicity in the Hickean sense.

Interestingly because of the constraints of the JVM in Clojure recursion is a loop (recur):

(def factorial
  (fn [n]
    (loop [cnt n acc 1]
      (if (zero? cnt)
        (recur (dec cnt) (* acc cnt))))))

loop [cnt n acc 1] specifies the initial values while in recur (dec cnt) (* acc cnt) the names (by position) are rebound. On the other hand mutual recursion with trampoline is more expensive (trampolines to avoid stack growth).


Yes, me too.

I completely agree with you about this, simply based on the official material would I probably see it very similar as you.

I was in a programming session with a very seasoned programmer and he showed me a different side of it.

I linked him the blog post regarding to the issue with Go’s error handling, lets see what he tells us. :slight_smile:

EDIT: Well, he answered that he also thinks the explicit error handling is one of the major strengths in Go.

In C and Java are such things much more error prone, he also works a lot with Erlang. He also sees less sense in hiding errors in functions, since this makes the whole code less readable.
(So as suggested in one of my links below)


Go’s deployment is simple, deployment in Clojure is familiar?
Go structs are simple compared to classes, to make gofmt default is simple, the comment handling for global variables is simple too.

To implement an error type is simple, I guess?
This might be considered as simple as well. :smiley:

And yes, it is also familiar to people who come from a C language.
Clojure is familiar to people who come from Lisp?

Besides this, there is a chance to oversimplify things.
Binary code is simple as its best. xD

Go is concise, the language is small and still useful.
This is also simple :wink:


Not interesting, unusable I’d say…

Aside of what is already said in the linked blog post, you can’t do enough with error it self.

All it allows me is to check if is nil or get a string representation of it. In some very rare cases this is circumvented by composing local error interfaces with the global error interface, where the local interface gives you additional information. But I have seen this only in stdlib so far, not in external libs.

So basically all you have to work with is a string and you have to parse it to find out what kind of error actually happened to branch on it and do case-based error handling.

Eg.: You can’t decide if database connection failed because of a network problem or because of wrong credentials. All you can do is to slap the returned errors string representation at the users face and tell him to try later. Well, or parse it (and pray noone fixes the typo in “pasword”[1]) to branch and give proper messages and set up retry handling, because I want exponential retry on network problems but just quit on invalid credentials. And this is only one of the occurences I had in my go-life.

[1] It has been fixed and because of gos bad dependency management we weren’t even able to fix the deps version, but had to check for both messages version, with and without the typo because we never could be sure which version the build-server had. Man we were happy when we discovered vendoring of dependencies and even happier when we found tools that pull transient dependencies into the vendoring tree…


Hi NoobZ :slight_smile:

I appreciate your contribution and guess I would run into those issues, once I dive deeper in this languages.

Here is one article which seems to tackle the issue about error handling: https://opencredo.com/why-i-dont-like-error-handling-in-go/

And here is another tool, while I guess you already know it:


I think more problems are with bigger projects due that go has flat type system.
You have two options either go unsafe or generate code.
I saw one presentation that 40% of code was generated.
For small projects , some dev ops tools , cli go could be fine.


Generics, or the lack of, is just another problem… But that nothing to do with the original FP vs C discussion.

But anyway, as I think about it, comparing FP to C is a bit like vegetables vs. apples.


Yeah, I hope too that they add generics in 2.0

About the type system: Several remarkable Go programs work quite well, such as dgraph.

I think, as always in such cases, is it probably a huge difference, HOW you use a language and as someone who has less experience in such one, is it probably easy to oversee some practices which are potentially game changing. :slightly_smiling_face:

This is why I see the opinion of somebody who has written a large application in that specific language as useful.

Is anybody here?


Yes I agree would be interesting to know what authors of these projects think about Go language



I like to note:

Not Go-specific, but this talk from Rich Hickey (author/inventor of Clojure) about simplicity, shows how important and pragmatic simplicity is. And it’s not about having fewer things at all. I could almost remember an equivalent quote from Rob Pike for each part of this talk.

No matter what programming language you use, this talk is a nicely arranged set of concepts around simplicity.


My point is that (at least in my understanding) Rob Pike’s use of “simplicity” has very little to do with Rich Hickey’s version of “Simple”.

Rob Pike’s concept of “simplicity”:

  • seems to relate to language features being basic (possibly even low level)
  • and that those features are easily recognizable (i.e. understandable) by those who are already practicing imperative programming (i.e. familiar)

Rich Hickey’s idea of “Simple” revolves around

  • being “un-complected” - i.e. designed to avoid interweaving things that benefit from being kept separate.

The metaphor is far perfect but
Benefits of Simplicity
While yarn is a basic enough medium, using it to implement a toy castle is going to result in a complected implementation - i.e. introducing changes while it’s being implemented or after it has been completed is either impossible or a nightmare.

You must become enlightened in the ways of writing simple code and I can help you along that path but you must walk that path.

To me Rob Pike and Rich Hickey are using similar words but are actually referring to entirely different concepts which could potentially be in conflict (i.e. Go’s “simplicity” is not a path by default to Rich Hickey’s idea of “Simple”).

For example I would describe the BEAM’s approach to concurrency as “Simple”. Code inside a process is entire sequential (even the sending and receiving of messages). Concurrency doesn’t happen inside a process but is a result of how the BEAM handles multiple processes and the messages between them.

Clojure tries to “Simplify” concurrency by hiding thread management away in core.async and adopting the Communicating Sequential Process model.

Go also adopted CSP with Go routines - while at the same time supporting sync.Mutex which tends to lean towards “complect-ing” matters.

From Kevlin Henney - Procedural Programming: It’s Back? It Never Went Away (2017)

I’ve often joked that instead of picking up Djikstra’s cute acronym we should have called the basic synchronization object “the bottleneck”. David Butenhof - comp.programming.threads, 2005-05-17


There is also TiDB, which does the same for MariaDB, if you are interested :slightly_smiling_face:

Yes, I love this talk, its legendary and as you can see a few posts above yours is it already mentioned in this thread. :slightly_smiling_face:

I also already declared were Go is simple in this sense, it got just ignored until.

Rich Hickey disagrees with you



I’m aware of that - and it’s also a misconception that Erlang set out to implement the Actor model (also: Erlang is not a implementation of the Actor model).

I also already declared were Go is simple in this sense, it got just ignored until.

This is where I disagree - I have yet to be convinced that Go’s touted “Simplicity” will lead to that version of “Simple” (i.e. un-complected, wieldy code).


Well, you can disagree, while this does not make my statements untrue. :slightly_smiling_face:

I havnt said its completely simply - nor that I consider this as desirable - I simply counted a couple of things who ARE simple by the definition of Rich Hickey and the lexicon.

This is not an opinion only, this is an objective observation.

Elixir and a huge load of other languages are at least so complex, with some benefits on this side and some disadvantages on the other.

This is why I am asking myself, why experienced developers discriminate this one language and I conclude that this is simply based on their subjective experience, rather than objective facts.

I mean honestly:

‘Go is garbage’ and ‘its error handling is unusable’ are obviously incorrect statements and highly biased opinions.

You ask me above how I would counter ‘these obviously biased concerns’:

I think obviously biased concerns counter them self. :wink:


It’s easy enough to dismiss “experience” these days:

A new scientific truth does not triumph by convincing its opponents and making them see the light, but rather because its opponents eventually die, and a new generation grows up that is familiar with it. Max Planck

But it’s also true that popularity doesn’t equate to quality. In this industry

happens all too often. I was genuinely interested why you liked it. Nothing’s perfect and maybe I’m overlooking something about Go but opinions about it seem polarized. I myself was once excited to be able to learn and use C (and later C++, followed by Java etc.) - these days I wouldn’t share the same enthusiasm with my former self - it has valid use cases and there are instances where I might dust it off but it is hardly the first thing I’d reach for.

However, again my personal opinion, I disagree with drawing a straight line between Rob Pike’s use of “Simplicity” in connection with Go and Rich Hickey’s “Simple is Easy” talk that seems to be all too popular these days. In my opinion it shows a misunderstanding of what it takes to write “un-complected and wieldy code” - programming language features aren’t going to make that happen by default.


As someone who uses both Go and Elixir, and has few Go services serving hundred thousands request per minute. My view is Go is solving different kind of problem than what Elixir does.

One is performance and two is static typing. Elixir lose in both front, but it helps developers iterate faster on solving domain problems. My comparison to Elixir are to JRuby, it similar when it comes to domain problem solving but Elixir is just faster also kind of predictable.

About Go error handling, it sucks and also make code test coverage looks bad, but it is what it is. Go also comes from system programming in mind hence the tooling is the one who catching up.

Go constraints I think make me code better, thinking how my package should work with go get is one thing what bounded context should use for and Non-cyclic dependency makes me think twice how my dependency graph should be. All in all it forces you to think about how to package your code to be reusable.


I have downloaded the slides to iterate based on what I remember, but it turned out to be a big tasks. So I fall back to essential things that in my opinion are the essence of this talk.

First, the context should be recalled. Rob Pike’s goal and environmental complexities that he was facing were different that Rich Hickey. On the case of Go, as strictly stated by Rob Pike it meant (the initial goal) for replacing parts of their system that were implemented in C++. Although Go later diverged from the initial goal and turned out to be a nice general purpose language, loved by many, including those came from dynamically typed languages such as Python. Go needed a garbage collector and it needed to be compiled fast. Also dropped feature to make it simple enough (in that context) to produce large maintainable code bases. On the other hand Clojure had not such goals and Rich Hickey had not to implement the garbage collector and other parts of the runtime. Instead he had to adopt JVM in smart ways that allowed Clojure to have enough pragmatic interoperability with the underlying VM, while being a descriptive Lisp.

Due to the context in which Go born, complecting things are easier compared to Clojure, yet still it is neither by design nor a by-product of just writing Go. It’s absolutely intentional when it happens and Go leaves things clear enough and does not hide it. Go tools do a nice job on this matter (vet, lint, etc).

The two things I pick from that talk that Rich Hickey emphasised greatly are data and polymorphism a la carte.

Rob Pike has a very similar point of view about data, to that of Rich Hickey. In Rob Pike’s 5 Rules of Programming, number 5 states:

Data dominates. If you’ve chosen the right data structures and organized things well, the algorithms will almost always be self-evident. Data structures, not algorithms, are central to programming.

Which is very similar to Rich Hickey’s way of approaching data, with same strong emphasise.

As for polymorphism a la carte, Go interfaces are exactly that.

A third thing that I’ve remembered is about (something like) decoupling, when Rich Hickey said if A is calling B directly, it’s complection; stick a queue in there. Again channels in Go play exactly that role (of-course overloaded with mechanisms for coordination).

Personally, I’m moving in a direction that does not ends in adding generics to Go. Actually if I could remove another thing from Go, it would be structs - which absolutely is not possible.


Simple Made Easy is transcribed with some of his other talks on Github.

On the other hand Clojure

I was never left with the impression that Rich Hickey implied that Clojure had any kind of magic “Simplicity”. Producing code that is “unentangled, not twisted together with something else” is the developer’s responsibility. A lot of the talk focused on the fact that “easy” (sticking to the familiar) has a tendency to lead to complexity while you have to constantly work at “simple” (unentangled).

In reference to Clojure the idea was mostly that LISP does not have the reputation of being “easy” which is mostly based on unfamiliarity rather than difficulty - the ideas that LISP is based on (and it’s implementation) aren’t complicated.

polymorphism a la carte

Seems this is often interpreted as a reference to Clojure offering multiple strategies for polymorphism - Go’s interfaces seems be just a choice of one.

I’m moving in a direction that does not ends in adding generics to Go.

By all accounts Go is what Google wants it to be - it has been in development for at least nine years and Rob Pike always emphasizes that there is no point in homogenizing Go with all the other programming languages by adding more features.

So while people keep hoping for Generics, it doesn’t seem that Google thinks they are necessary. And to be fair I recall signifcant criticism with the way Java implemented Generics.


I remember seeing something along these lines too. I basically agree that CSP style concurrency (used in Go and I think also Clojure async) is a simpler idea than actor-like model.

However, I also think the simplicity is not an absolute property, but rather a thing which needs to be evaluated in the context of the problem. For example, when we’re talking about server systems, where a bunch of stuff happens, most of which are mutually unrelated, I feel that the actor approach is a much better fit, and that it offers some fundamental guarantees which cannot be achieved when queues are the building block for concurrency.

The problem with queues is that since activities are anonymous you can’t do any of the following:

  • enumerate your activities
  • ask the runtime for some info about any particular activity
  • forcefully terminate an activity
  • propagate a failure (crash) of one activity to other activities

I find these features very important because they allow me to get the following properties:

  • isolation of negative effects of individual failures
  • self-healing ability
  • support for troubleshooting the production system

All of the above is possible in BEAM precisely because activities (processes) have identities. I’ve spoke a bit about this at my Solid Ground talk (the link points to the part where I discuss the benefits of identifiable activities).

It’s also worth pointing out that decoupling can be done on top of the coupled approach. In fact, I think that in proper Elixir/Erlang codebase this is frequently done when we use registered local names or Registry. In such scenarios, we don’t keep a pid of the receiver, but instead discover the desired target lazily through a registration facility.

Finally, I think that there are other kinds of software where the properties above are less important, or maybe even irrelevant. For example, in a one-off program with all-or-nothing semantics, there’s no point in being fault-tolerant since every activity must succeed for the program to succeed. In such cases perhaps queues would make more sense as a basis for concurrency.

But when it comes to software systems, I tend to think of them as a collection of activities, some being independent, and others mutually collaborating. And with such view, I think that the actor-like model is a much better fit precisely because it has activities as first-class concepts and foundational building blocks.