I'm 3.5 years into using Go exclusively as well, and this rings very true to me with regard to generics:
> Interfaces are good enough 99% of the time.
Generics would be really nice for generic data structures (heaps, trees, etc), but code generation is ok at that.
Generics could allow for some nicer (and safer!) nil handling and error checking, but I think the benefits-vs-complexity are less clear than with generics for data structures.
I think it's hard to quantify the massive benefit Go's simplicity is to onboarding developers -- especially for a new language where hiring experienced devs is next to impossible. The ease of onboarding is reason enough for businesses to consider Go as over an org's life a lot of time will be spent (wasted?) onboarding.
Any language features which increase cognitive overhead had better offer some extremely compelling benefits to outweigh an increased learning curve.
> And I don’t mean interface{}. We used interface{} rarely in Juju, and almost always it was because some sort of serialization was going on.
This has been my experience as well. Whenever I hear someone complaining about interface{}, I wonder what they're doing. I think it's often people used to having generics or a dynamic language trying to follow similar patterns in Go and not considering alternative patterns.
I've never used a language that didn't lack type information at the edges (where serialization occurs). Even using strongly typed serialization (eg Protobufs) in a language with strong type features and patterns (eg Java) I always see a fair amount of glue code converting from "weaker" serialization types to stronger internal representations.
As long as those edges are architected to be easily testable (even fuzzable!); I don't see it as a problem. You have to convert from bytes-on-the-wire to typed variables somehow.
>Generics would be really nice for generic data structures (heaps, trees, etc), but code generation is ok at that.
Either code generation is an implementation detail of generics, or this is an afterthought that adds incidental complexity and was almost assuredly better off being a core language feature.
>I think it's hard to quantify the massive benefit Go's simplicity is to onboarding developers
This is really only applicable to small applications using new languages where the main cognitive onboarding is learning a new language/paradigm. As soon as you reach a certain size of application, the frameworks, architecture and domain knowledge heavily outweigh the cost of learning even the most esoteric of language features.
>Any language features which increase cognitive overhead had better offer some extremely compelling benefits to outweigh an increased learning curve
I wonder what kind of language feature you're talking about? The whole idea of generics in a more functional oriented language is to reduce cognitive overhead. The beauty of parametricity is it takes things away from the developer to help them reason about the code!
Our (very large) team of engineers use this to great affect throughout our codebases. There is no such thing as a silver bullet, but this comes as close as I've seen in the 12 years I've been an engineer (from startups to a Fortune 10 company).
> Any language features which increase cognitive overhead had better offer some extremely compelling benefits to outweigh an increased learning curve.
This is a common misunderstanding that occurs (I think) because most people only know C++-, Java-, and C#-style generics, which can be conceptually complicated, because of the often tricky interactions with the type system (or, in the case of C++, the use for metaprogramming).
In contrast, module-based genericity (SML, OCaml, Ada, Modula-3) is conceptually pretty simple, as it avoids complicating the type system. Its main downside is (relative) verbosity, but Go has never really eschewed verbosity.
It struck me the other day that when using Go codegen tools which generate packages based on a template, e.g. [0], the Go developer is doing manually what the OCaml compiler will do with functors at compile-time. The concepts are fundamentally the same...the effort just happens in different places.
They're very different. Generics in languages that have them are typed—you have to declare up front the methods that your generics support. That's the entire thing that makes ML functors functors.
By contrast, generics in languages like C++ and D, as well as the code generation tools for Go, are untyped—you can call whatever functions you want on your types, and if it doesn't work it fails at template instantiation time. This causes the confusing template errors people see in C++.
You are, of course, absolutely correct: compile-time awareness of semantics vs just syntax is an important difference.
I guess the point I was getting at – though improperly phrased – was that if current Go tooling is similar to templates, and templates are similar to functors (in that you're instantiating both but the latter have additional checks for correctness), then perhaps module genericity wouldn't be as tough a sell to the Go team/community.
>>> I think it's hard to quantify the massive benefit Go's simplicity is to onboarding developers -- especially for a new language where hiring experienced devs is next to impossible. The ease of onboarding is reason enough for businesses to consider Go as over an org's life a lot of time will be spent (wasted?) onboarding.
Agree. I feel it so much.
I stopped counting the companies I couldn't join because they had exotic languages or just the latest fad of the year.
That's a very effective way for a company to stay away from having any experienced engineer while making it very hard to recruit at all (note that both effects amplify each other!). The hardest and newest the languages, the worst it is.
As an employee, that's a painful way to have a company cancel a decade worth of experience. I'm not interested in starting fresh again. Bye.
Accordingly to your logic then we should have no language other than C because everyone had decades worth of experience in that language and was not interested in starting fresh again.
From my point of view I was very relieved when imperative languages and their adept seemed finally to embrace better tools after Y2K.
Apparently now there is Go that follows up with that style (that was perfectly fine for a 10 years old ages ago) and it is making again adepts.
For me this new spring of imperative languages seems more like the winter of programming.
The only "new" language that captured my interest is F#, but obviously all the go proponents will be horrified by the simplicity of type providers and all the nice "magic" things that are not easy unless you spend at least half an hour of your time to understand them.
F# is completely not an alien in any regard, it is basically an SML (a language-predecessor of OCaml/Haskell from 90s) for .Net.
I can say in the very same manner that Go is a total alien since it does not use Hindley–Milner type system or higher kinded types and throws under the bus a decade of muscle-memory coding.
> Interfaces are good enough 99% of the time.
Generics would be really nice for generic data structures (heaps, trees, etc), but code generation is ok at that.
Generics could allow for some nicer (and safer!) nil handling and error checking, but I think the benefits-vs-complexity are less clear than with generics for data structures.
I think it's hard to quantify the massive benefit Go's simplicity is to onboarding developers -- especially for a new language where hiring experienced devs is next to impossible. The ease of onboarding is reason enough for businesses to consider Go as over an org's life a lot of time will be spent (wasted?) onboarding.
Any language features which increase cognitive overhead had better offer some extremely compelling benefits to outweigh an increased learning curve.
> And I don’t mean interface{}. We used interface{} rarely in Juju, and almost always it was because some sort of serialization was going on.
This has been my experience as well. Whenever I hear someone complaining about interface{}, I wonder what they're doing. I think it's often people used to having generics or a dynamic language trying to follow similar patterns in Go and not considering alternative patterns.
I've never used a language that didn't lack type information at the edges (where serialization occurs). Even using strongly typed serialization (eg Protobufs) in a language with strong type features and patterns (eg Java) I always see a fair amount of glue code converting from "weaker" serialization types to stronger internal representations.
As long as those edges are architected to be easily testable (even fuzzable!); I don't see it as a problem. You have to convert from bytes-on-the-wire to typed variables somehow.