
Notes on the Go2 Generics Draft - ainar-g
http://jmoiron.net/blog/notes-on-the-go2-generics-draft/
======
nemo1618
I'm glad I'm not the only one sad to see generics invading a perfectly good
language.

Programmers love generics because they enable higher-order abstractions, and
programmers love abstractions -- code that isn't DRY is like an itch we need
to scratch. Programmers also hate special cases, because they feel restrictive
and inconsistent: I recall quite a few people protesting that Go's 'range'
keyword shouldn't be restricted to a handful of built-in types, but rather
should support any type implementing an Iterator interface.

But Go was not designed to be perfectly consistent or to enable high-order
abstractions. It just aims to be productive at scale, and that often means
restricting the programmer. Go tries to be _non-magical_ , and sadly that can
take much of the whimsy out of programming. You can't chain together operators
in point-free style, or add a property to every 'Object', or directly
increment a string, or anything like that. In other words, it's a terrible
language for code golfing. But that sort of code has no place in a production
environment anyway. It's "clever" code that gives the programmer a little
dopamine hit when he writes it, and his co-workers a headache three months
later. Those are misaligned incentives.

So I worry about generics because they let you abstract with wild abandon.
They let you inject a little magic. And I fear that programmers will be
seduced by their love of magic, and I'll be the one who ends up paying the
price.

~~~
civility
Writing the exact same code for float and double (and possibly complex float
and/or complex double) sucks. You've created some straw man about dopamine
junky programmers because you don't need generics for whatever it is you do.
If you wrote numerical algorithms you'd be annoyed at any language which lacks
generics.

~~~
cdoxsey
Ironically generics don't necessarily solve this. C# requires multiple
implementations of numeric methods because int/float/etc don't sit in a type
hierarchy.

It also doesn't really work in Java either because you have to use the Object
types.

Even in rust this looks pretty complicated: [https://travisf.net/rust-generic-
numbers](https://travisf.net/rust-generic-numbers)

Maybe it's easy in c++?

I've seem a similar comment made on almost every discussion of this issue...
are folks just not aware of the limitations with generic implementations?

~~~
annywhey
In agreement. IMHO generics basically have one place where they work well:
abstract containers. Your queues, linked lists, what-have-you can benefit.

But most other data structures? Nope. Too much of the algorithm depends on the
primitive type.

And that makes generics a nice boon for computer scientists and certain
library authors, but of middling benefit for day-to-day coding. If the
container works, you can copy-paste-modify your way to the types you want, or
automate the same in a macro or code generator. It's not beautiful but it
doesn't have to be.

~~~
int_19h
Having coded C# for many years now, generics are used for a _lot_ more than
just containers. There's a great many things that can be generalized. Just
look at any large C# project on GitHub.

------
hugofirth
The author makes some interesting arguments, but they are all predicated on
the idea that generics are somehow hard to grok or use?

Having helped teach Java to many people with less than a year's programming
experience at university, I refute this.

Bear in mind we're hardly talking about higher kinded types here. Generics are
a simple abstraction over a lack of type information which allows you to write
and maintain a lot less code; something which has been repeatedly demonstrated
to reduce the incidence of bugs.

Personally, I am encouraged that the Go team is flexible enough to change
their position. That gives me more confidence in the future of the language,
not less.

~~~
laumars
I keep hearing people say things like "the Go team are changing their
position" but I think what a lot of people missed is that the Go team were
never against implementing generics in version 2. Quite the opposite in fact
as they actually often said it was a consideration for Go v2.

What they repeatedly opposed was rushing generics into a v1.x build as that
could break things.

The real issue is that many of the "haters" (and I hate using that term but it
really was largely just individuals who decided that didn't like Go from the
outset anyway so weren't exactly day to day Go developers) didn't think the
slow and methodical approach was good enough.

Sometimes it feels like those who are the loudest critics of Go aren't even Go
developers and instead just like to shout about how amazing their preferences
are because it does _xyz_ differently. And frankly I get a little fed up with
all the psuedo-religious zealotry some have towards programming languages.
It's nuts. Yet that's exactly how many of the language-specific topics end up
on HN and why many on here could be forgiven for not realising that the Go
team have always been open minded about changing Go; they've just been
stubborn about the timelines of such changes.

~~~
viraptor
> critics of Go aren't even Go developers

This doesn't make the criticism invalid. I tried Go, found the lack of
genetics / gopath / depends management too annoying, went back to other
languages. I'm going to try it again after V2 is released.

If only people continuing to use X could criticise X, we wouldn't get much
progress.

~~~
joshuak
I’m so conflicted about this comment because I have made nearly identical
comments in the past.

I think I’m going to have to change my stance on this point, however. There
have been so many occasions that something about Go bothered me, and I then
later discovered was a prerequisite to leveraging a much simpler programming
model, that I am humbled by how much more I had to learn about programming.
And I have to admit that others before me said as much, but I didn’t believe
them.

Sometimes one just isn’t competent to render a useful opinion.

If you haven’t seen the movie, read the book or eaten at the restaurant, the
directors, authors, and chefs should rightfully ignore your criticism. And I
for one am glad the Go authors ignored criticisms like mine, I am a much
better programmer now then I was then because I learned something new.

Although I will admit it was difficult at times. It’s hard to go from being an
expert at something to a beginner at something you feel should be essentially
the same.

~~~
viraptor
I feel like you're saying the criticism has to turn out right or wrong. I
don't feel that's the case. A criticism is just an opinion (based on facts or
not). Ignoring them will lead one way, addressing them another. Some people
will like either one of them.

I think criticism from people who stopped using X is a valid opinion even if
it's ignored and if other people are happy it was ignored. You can't please
everyone.

~~~
laumars
What the GP was saying is that a critique from someone who actively uses
something should carry more weight than a critique from someone who doesn't
use something because they happen to prefer the goals of something else
already available anyway.

This was also the point I was driving at. I do respect the opinions of other
developers outside of the Go community as well but as you said, you cannot
please everyone. When many of the loudest critics were those who seemed to
miss the point of Go or at least we're disinterested in the goals of Go, it
got quite irritating to constantly read how "Go is terrible" when clearly it
is a perfectly decent language for a great many developers. It's the same
thing with the roadmaps, those who criticised it the most were often the
developers who werent Go developers and thus didn't depend on the assurances
Go offers.

------
bww
I’m a fellow generics pessimist. Having come to Go from Java some 6 years ago
I initially found the lack of generics a curious, sometimes frustrating
omission.

After years of using Go daily and reading a long succession of posts on the
go-nuts mailing list wherein Rob Pike, et al, repeatedly and staunchly
defended the lack of generics as necessary – even beneficial – in the pursuit
of designing a small, readable, coherent language, I’ve since come to believe
that decision was entirely correct.

Perhaps nobody technically promised there would never be generics in Go’s
future, but it’s undeniable that they run contrary to those stated design
goals. As currently proposed, they will add considerable complexity to the
language in exchange for questionable benefit.

I’m not sure the world needs another kitchen-sink language that eschews
clarity for the unrestrained addition of features. If you want that, there are
already plenty of options for you.

~~~
everybodyknows
Speaking of Rob Pike, don't see his name on any of the Go2 proposals. His
lucidity and circumspection are sorely missed.

Could we be witnessing the psychological phenomenon of a "second-system
effect" \-- as described in The Mythical Man-Month -- writ very large?

~~~
ainar-g
The only person from the original three creators who still actively takes part
in the language's evolution seems to be Robert Griesemer. Ken Thompson is
retired, and Rob Pike seems to have moved to other projects (Upspin?). Robert
Griesemer is still active, but mostly "debugging" the language specification.

The impression I get is that Russ Cox is pretty much the Chief Designer right
now (pardon the Sergey Korolyov reference). The original three authors have
said that they would not add a feature to the language if one of them opposed
it, which is how they kept it simple. I wonder if rsc has anyone to say "no"
to him.

------
Animats
That's elaborate. More elaborate than expected for Go.

I was expecting something more like explicit parameterized types. Go already
has those - maps and channels are parameterized types. You just can't define
new parameterized types. Extending Go to allow those would be a smaller step.
That doesn't get you overloaded functions, though.

The designers of this wanted the ability to define a new function F(T x) which
works for any T upon which a known list of functions can be applied. Then they
wanted that to work for separate compilation. So there's all that "contract"
stuff to carry the info about what F needs from T. Seems clunky. It violates
the rule "You should never have to tell the computer something it already
knows." It's clear how the constraints they set upon themselves lead there,
but it's still clunky.

 _This design does not support template metaprogramming or any other form of
compile-time programming._

Whew! That's a relief.

 _" We expect that most people will not write generic code themselves, but
many people are likely to write packages that use generic code written by
others."_

In other words, maybe it is a little too complicated.

~~~
cbolton
_It violates the rule "You should never have to tell the computer something it
already knows."_

Not really: the contract is an explicit list of requirements with API
compatibility guarantees for future versions. The computer cannot guess that
from the current implementation.

------
realrocker
I have written about 10+ medium and big projects in Go for production over
last 6 years. They were written mostly for CI/CD, APIs, cron jobs and various
pipelines in e-commerce and consumer electronics domains. Have personally
never needed generics or have felt that I can improve the code by using
generics. I also have quite a bit of Java experience so I do know why you
would need generics, but it just never came up in Go. Maybe my opinion will
change with the new proposal getting implemented, but at this point I don't
see how.

------
zmanian
It's impossible to defend the lack of generics in golang in the face of the
fact that two of the larger open source projects both invented their own
generics implementations.

[https://medium.com/@arschles/go-experience-report-
generics-i...](https://medium.com/@arschles/go-experience-report-generics-in-
kubernetes-25da87430301)

[https://github.com/google/gvisor/blob/master/tools/go_generi...](https://github.com/google/gvisor/blob/master/tools/go_generics/generics.go)

~~~
cshenton
It’s weird to see complaints about code generation causing a too big code base
at compile time when code generation is exactly what a compiler will do behind
the scenes for generics.

~~~
willtim
Not necessarily, specialisation is only argubly required for unboxed types.
Java actually implements "Generics" without any specialisation at all, it
boxes all the primitive types (rather controversially).

~~~
dullgiulio
And that has a baggage of problems. The best way is what C# does, which
incidentally is also what Go does with
maps:[https://dave.cheney.net/2018/05/29/how-the-go-runtime-
implem...](https://dave.cheney.net/2018/05/29/how-the-go-runtime-implements-
maps-efficiently-without-generics)

~~~
willtim
The C#/.NET solution, while very good, has some problems too. By implementing
generics so deeply into the runtime, it becomes very difficult to enhance the
support in the future, for example adding higher-kinded types (which the F#
folks have long been asking for).

I actually quite like the Haskell approach of having a "Specialisation"
annotation. I believe Scala has this too.

------
scoom
Its wonderful how much Go wants everyone to repeatedly develop container data
structures. That way everyone gets their own artisanal bugs.

~~~
coldtea
Well, that makes sense, coming from some of the people that gave us C.

------
Exuma
Can someone explain in terms to someone who hasn't really used a static typed
language what "generics" are? I've only used javascript and ruby.

~~~
jniedrauer
Consider this function signature:

func SomeAdditionFunction(arg1 int, arg2 int) { fmt.Println("Sum:", arg1 +
arg2) }

This function will only accept a pair of integers. In order to perform
addition on floats or int64s or any other number type, you would need a
separate function.

Go has the concept of an empty interface (interface{}) which can accept any
type. But this is not really a generic because you have to assert that it is a
specific type in order to be sure what it actually is at runtime. This
function for example, will not compile:

func SomeAdditionFunction(arg1 interface{}, arg2 interface{}) {
fmt.Println("Sum:", arg1 + arg2) }

But this will:

func SomeAdditionFunction(arg1 interface{}, arg2 interface{}) {
fmt.Println("Sum:", arg1.(int)+arg2.(int)) }

In a language like Java, I could write this function to accept any type for
which the + operator is valid, and it would still be type safe at compile
time. I would not need to assert the types like I did above.

~~~
mseepgood
> In a language like Java, I could write this function to accept any type for
> which the + operator is valid, and it would still be type safe at compile
> time. I would not need to assert the types like I did above.

Really? No. Not in Java.

    
    
      static <T extends Number> void someAdditionFunction(T arg1, T arg2) {
        System.out.println("Sum:", arg1 + arg2);
      }
    

"error: bad operand types for binary operator '+'"

~~~
dtech
That's because + is a java built-in unavailable to normal types. Usually
something like an add method is used instead. It does not detract from the
underlying point.

------
jahaja
I'm a bit sad about the lack of acceptance for pluralism in widely used
languages. The effort to get Go in line with other languages just seem so
disproportional.

~~~
jy3
Reading HN, it feels like some people just want every language to have the
same features and have them implemented the same way.

Sad indeed.

~~~
bodas
Go is a tool, it's not a religion. People are allowed to criticise it, and
they don't have to temper their criticism just because the Go team or Go users
have a different opinion. Go is made by Google it's not like it's some kid's
school project.

------
atsjie
The proposal reads like an attempt to add generics to a language that was not
conceived to include it in the first place.

It looks complex.

~~~
vorg
I agree. The real problem is they're trying to add generics to Go _and_ make
Go 2 backwards-compatible with Go 1. Doing both generates the complexity, just
like with Java 5. Generics in a language are good, but Go will cross the line
from simple to bloated as soon as these generics are added. To remain a simple
language with generics, Go 2 would need to give up backwards compatibility
with Go 1, something which the suits at Google would veto if any techies there
actually tried it.

------
RcouF1uZ4gsC
Yet another language tries to bolt on generics after the fact and finds that
doing so results in awkwardness. Note to language designers: if you are
creating a general purpose language, you will eventually need to add generics.
You can either do it right at the beginning, or else you have to bolt it on at
the end. Rust gets kudos in this regard for having well designed generics from
the beginning.

~~~
Filligree
Rust has parametric polymorphism, not generics, and doesn't have subclasses.
This makes it not quite the same thing.

~~~
dbaupp
Rust does have generics. There's little value in constructing a distinction
between "templates", "generics" and "parametric polymorphism", at least not
for the parent comment, which was likely intended to mean "Rust has a well
designed system for working with 'unknown' types". (Also, maybe you could be
specific about what you think the difference is.)

Go also doesn't have subclasses, so that doesn't seem relevant.

~~~
mcguire
They're the same thing:

"Generics" is a term from software engineering, describing how the concept is
typically used.

"Parametric polymorphism" is a description from a type theoretic standpoint.

"Templates" are an implementation strategy.

~~~
dbaupp
I understand what these words mean... At least, I understand the variety of
meanings they have: they're not always used to mean the same thing. For
instance, people will rightly say that Java doesn't strictly have parametric
polymorphism because of dynamic type casts, but they will say it has generics.
Other people might draw a distinction between generics and templates, with the
former being constrained (with type classes or similar) and the latter being
macro-like.

However, I don't think these are actually particularly relevant to the
original comment (and, I really think that Rust probably satisfies "generics"
more than "parametric polymorphism", because one can also do generic casts).

------
stewbrew
Every time I read a discussion about generics in Go, I remember discussions on
the Small/SmartEiffel list where people argued that Eiffel doesn't need this
or that because it can be emulated with a feature already available in the
language. Well, Eiffel is history now.

