
Summary of Golang Generics Discussion - signa11
https://docs.google.com/document/d/1vrAy9gMpMoS3uaVphB32uVXX4pi-HnNjkMEgyAHX4N4/edit#
======
coldtea
> _As with any feature it should solve a set of problems, if the problem isn’t
> solved in the best way possible by the feature then it’s either not a good
> feature or of very limited value._

This is disingenuous -- just to set an artificial barrier against generics.

Go doesn't solve any problem in the "best way possible":

\- "Blessed" containers like Go's hash tables are not "the best way possible".

\- The way it handles goroutines/channels has issues (mutability/pointer
issues, not pre-emptive, etc). Again, far from "the best way possible" (that
would be Erlang maybe).

\- The GC was far from the "best way possible" or even "really good".
Especially on the earlier versions (and crap on 32-bit).

\- Losing type checks by having to use interface{} for generality, or
resolving to BS textually generated code with custom string templating is not
"the best way possible".

So why only Generics has to be "perfect or bust"?

And then there's this gem, about the (lack of) need for generic data
structures:

> _map /slice suffice for most of the cases encountered in programming._

...

Or this "con", about having generic to help with functional fold/zip/map:

> _The fastest solution needs to take into account when and which order to
> apply those transformations, and how much data is generated at each step_

So, in other cases the hit from interface{} is OK, but suddenly now those
operations have to be "the fastest solution".

(Not to mention that the fastest solution, application order etc are
orthogonal to Generics).

~~~
egonelbre
Thanks, didn't intend for it to end up on HackerNews - at least not yet. It's
still the first draft, most of it I wrote up in ~2hours. I mentioned on the
forum that this document (currently) is highly biased towards my views, this
is unfortunate, but this can only be fixed after numerous reviews.

Thanks for pointing out the problems with wording. I'm slowly fixing those.
I've changed that "best" to "As with any feature it should solve a set of
problems, if there are better ways of solving the problems, those should be
used instead."... it's better but not perfect.

"in other cases the hit from interface{}" \- added that addition to the
alternatives section.

Generics don't have to be perfect, but it must be actually useful and it
mustn't compromise simplicity of Go.

~~~
waps
It doesn't mention the major inconsistencies in golang at all.

Go has generics. For arrays, slices, channels, maps, and some "standard"
library functions. Go has generic functions. "append" being the obvious
example. Go has polymorphic functions : append, make, ... If you look at the
compiler source, the type system has generics, to a large extent. It's simply
not accessible to normal programmers, instead only allowed for golang's
authors.

As if this is not bad enough. Go cheats the type system in thoroughly non-
obvious ways to get more C-like behaviours that obviously do not improve
safety or programmer productivity.

Go has _shudder_ return value polymorphic functions. Range being the obvious,
but not only example (range changes in meaning depending on it's parameters
AND on what you assign the result to).

As for your boxing argument. As soon as you use reflect, you're boxing
everything. Oh wait, if you use a package that uses reflect, of course you're
also boxing everything. Surely that can't be much ... hmmm half the standard
library uses reflect. Fmt, everything in encoding, text or html templates,
rpc, jsonrpc ... No need for boxing, or compile-time function evaluation or
generics (all present better solutions to this, for the CTFE solution see
D-lang).

Golang even has functions with type parameters. Make and new being the obvious
examples. Again, this is present in the type system (not just there, also in
reflect, things like printf, ...). It's simply not made accessible to us lowly
go programmers.

So can we please stop with the crap that generics aren't necessary ? That
nobody uses advanced type system features ? Or that polymorphism isn't
necessary ? It's crap, and obviously the golang authors don't actually believe
that. They just think that only they can be trusted to write such functions
and that their datastructures are all anyone ever needs. If you disagree with
that assessment (and everybody will, soon) Go is not for you.

So Go is simply a throwback to pre-80s programming languages, and a perfect
illustration of the frustrations that led to the development and extension of
the C++/Java/C# programming languages. If you give people the minimal
implementation of sorting an array of structs, it becomes blatantly obvious
why other languages are necessary.

The more I write Go, the more I yearn for C++. There is nothing in the C++
language that I can't do for my own datastructures/functions/... That is a
huge feature, and may I just say :

From my cold, dead hands !

Btw : there is a better solution to generics as well at compiler-level, that
is used in things like the CLR. First, generate unboxed versions of functions
where that makes sense. If specializations are possible for 1-bit, 1-byte,
2-byte, 4-byte and 8-byte primitive data types, expand those. Then for
anything bigger, like structs, create a boxed implementation, because for
structs there is no longer any advantage to working unboxed. Then make it
possible to pass in the version to be used in a parameter, so you don't have a
combinatorial explosion when many type parameters are given.

e.g.
[http://research.microsoft.com/pubs/64031/designandimplementa...](http://research.microsoft.com/pubs/64031/designandimplementationofgenerics.pdf)

~~~
egonelbre
> It doesn't mention the major inconsistencies in golang at all.

It has little relevance to "Generics". They are simply how Go is implemented,
the question is whether "Generics" as a user implementable thing should be
added.

> CLR

From my quick reasearch, it uses runtime code generation and Go must run in
environments where that is disallowed.

~~~
pjmlp
Regarding the CLR you have ahead of time compilers in the form of Mono for
iOS, Windows Phone, Bartok, ngen and now .NET Native.

How the generic code generation differs from the JIT approach I don't know.

------
djhworld
I find it amusing how angry people get about this, like really, vehemently
angry.

If this issue is so important to people, don't use Go, use C++, Java, D or
Rust. Don't waste your life arguing about something you'll never use, it's not
a productive use of your time! Think about how much time you could save!

Alternatively, propose a solution to the problem and try and gain some
traction to get it implemented into the language, or fork Go and implement it
yourself. There's evidently a hunger out there for generics in Go, but
everyone keeps assuming the responsibility lies with the Go Core team who's
priorities seem (right now) to be in the optimising GC/compiler area.

~~~
itg
So should people stop talking about the pros/cons of programming languages at
all? Because this can also go the other way. Another person can say: "If you
enjoy programming in Go, then use it but keep quiet and stop promoting it and
talking about how much you like it."

I haven't used Go at all yet, but I'm interested in hearing more about it the
good and bad parts, along with other languages. Telling others to not complain
at all doesn't do any favors.

~~~
tormeh
I agree, but I think there's something to be said for not complaining about
lack of generics in Go. We kinda got it the first 100 times it was said.

------
AndrewDucker
What I find frustrating is that they seem to think that there are only two
solutions - C++ (create a new type for each variant) or Java (erase the type
information).

C# does it differently to either - see here:

[http://www.jprl.com/Blog/archive/development/2007/Aug-31.htm...](http://www.jprl.com/Blog/archive/development/2007/Aug-31.html)

(The section marked ".NET Implementation")

Edit: And here's Anders Hejlsberg talking about the design:

[http://www.artima.com/intv/generics.html](http://www.artima.com/intv/generics.html)

~~~
masklinn
> What I find frustrating is that they seem to think that there are only two
> solutions - C++ (create a new type for each variant) or Java (erase the type
> information).

That, at least, is correct. Generics can be erased (compile-time only) or
reified (generic type instances exist at runtime).

C# uses reified generics, and Mono creates (created?) a reification for each
parameter typeset, Microsoft's implementation creates the same underlying
reification for all reference types as a space optimisation, but it still uses
reified generics.

There is a good helping of dishonesty in using C++ as the "reified generics"
example though, as C++'s templates do significantly more than just reify
generics (template specialisation, code generation, etc…) and that added to
the interactions between templates and other language features makes them
significantly more complex than e.g. C#'s, Rust's, Ceylon's, Kotlin's, and
most other instances of reified generics.

~~~
edgyswingset
The argument brought up regarding compile times is also a misnomer. C#'s
compiler pre-Roslyn is already very, very fast.

------
egonelbre
Didn't intend for it to end up on HackerNews - at least not yet. It's still
the first draft, most of it I wrote up in ~2hours. I made a mistake for not
putting the "Draft" note at the top of the page in the first page.

I try my best to be objective - obviously this isn't easy. This is intended to
be a review of both sides of the arguments. The generics discussion comes up
again and again - I made this document to stop arguments going around in
circles.

I will go over all the suggestions and add any missing information. Of course,
if you have some good overview of some particular generics implementation you
can PM me, or simply add that as a comment.

------
pjmlp
As usual, it lacks discussion about generics in:

\- Eiffel

\- Ada

\- Modula-3

\- D

\- MLton

\- .NET

\- Rust

\- Haskell

\- OCaml

\- Sather

\- BETA

\- CLU

Even if they overlap, it would be nice to see them being discussed. Not all
generics are born alike.

Personally, I don't care any longer. It is still better than just plain C.

~~~
bluecalm
I just want to point out that C actually supports generics in a form of
pointer to void.

~~~
wtf_is_up
interface{}

~~~
bluecalm
I was responding to a comment claiming that Go is better than C in discussion
about generic programming. I pointed out that C in fact supports generic
programming (actually by void pointers and function pointers). Why you (and
other downvoters) respond with the way to do it in Go isn't quite clear to me.
I didn't claim anything about Go. I claimed something about C.

~~~
pjmlp
Maybe because Go's approach, although lacking, is still better than C in terms
of type safety.

When you cast from void* to whatever type, the compiler will happily accept it
and bad things will happen if the type is wrong. Maybe not right away, thus
the program will bleed with corrupt memory.

With Go when you cast to the wrong type, a cast violation will occur and the
program will panic right away.

~~~
masklinn
I think that's memory-safety rather than type-safety: in Go (or Java or C#)
the types may not be correct (so it's not type-safe) but it'll fault at
runtime rather than possibly corrupt memory as C would.

------
qznc
There is only two ways to compile generics C++ (instantiation) and Java (type
erasure) style. [0]

Alternatives to these are just manual or semi-manual variants. For example, Go
people seem to like the "empty interface" approach. Well, that is Java-style
type-erasure done manually. The code generation approach is just C++-style
instantiation done outside of the compiler.

[0]
[http://beza1e1.tuxen.de/articles/generics.html](http://beza1e1.tuxen.de/articles/generics.html)

~~~
AndrewDucker
C# doesn't erase types, and it doesn't create a separate type for every
possible variant.

See the ".Net Implementation" section here:

[http://www.jprl.com/Blog/archive/development/2007/Aug-31.htm...](http://www.jprl.com/Blog/archive/development/2007/Aug-31.html)

~~~
pjmlp
This interview with Anders Hejlsberg is also a good source of information

[http://www.artima.com/intv/generics.html](http://www.artima.com/intv/generics.html)

~~~
qznc
So, C# does instantiation, but is usually clever about reference types.

I am not quite sure from the interview what happens about constraint types. It
seems the reference is cast into an Interface type (IComparable) and used as
such. In other words, boxing.

~~~
michielvoo
The arguments used for contrained type parameters can be checked by the
compiler, so no casting is necessary at runtime

"... C# does strong type checking when you compile the generic type. For an
unconstrained type parameter, like List<T>, the only methods available on
values of type T are those that are found on type Object, because those are
the only methods we can generally guarantee will exist. So in C# generics, we
guarantee that any operation you do on a type parameter will succeed."

Edit (more explicit quote):

"When you say K must implement IComparable, a couple of things happen. On any
value of type K, you can now directly access the interface methods without a
cast, because semantically in the program it's guaranteed that it will
implement that interface. Whenever you try and create an instantiation of that
type, the compiler will check that any type you give as the K argument
implements IComparable, or else you get a compile time error."

Furthermore (related to the CLR avoiding boxing costs):

"I'm just pointing out that we do fairly aggressive code sharing where it
makes sense, but we are also very conscious about not sharing where you want
the performance. Typically with value types, you really do care that List<int>
is int. You don't want them to be boxed as Objects. Boxing value types is one
way we could share, but boy it would be an expensive way."

~~~
qznc
What I wonder is: Take "SortedList<T> where T:IComparable". Now there is a
generic add(T t) method, which needs to call t.compareTo(x). As add does not
know the dynamic type of t, we don't know the vtable offset of compareTo for
compilation. Thus the compareTo call cannot be compiled to "load method
pointer from vtable; call it". We need something more expensive or JIT magic
(traces,guards,etc).

------
anonfunction
Interesting timing as I had just read a great blog post about getting around
the lack of generics in Go entitled "Living without generics in Go"[1] that I
found to be very enlightening.

[1] [http://www.weberc2.com/posts/2014/12/12/living-without-
gener...](http://www.weberc2.com/posts/2014/12/12/living-without-generics.txt)

~~~
BruceIV
Interesting post, but what the author doesn't seem to realize is that even
though _he_ isn't doing much generic programming, _someone_ needs to be able
to do it to write the libraries he needs to use. The proposed approach is
decent, but it reminds me of wrapping up STL container types in the amount of
useless boilerplate needed to achieve a single function (but worse, because
here the function is "type safety", whereas when you wrap an STL type it's
about e.g. ensuring some invariant on the members of a set)

~~~
weberc2
The author here. I'm not necessarily an opponent of generics, the post was
just a "how to deal with the current situation", so keep that context in mind.
:)

> someone needs to be able to do it to write the libraries he needs to use

I'm not sure what this has to do with what I wrote. As evidenced by the
`container/list` package, a generic implementation _can be_ distributed, and
we can build our type-safe wrappers around that (if type-safety is really that
important in your application--I haven't had much difficulty using the generic
container as-is).

I do agree that the boilerplate is inconvenient (pretty much by definition).
But it's fortunately also _trivial by definition_. People seem to think that
these wrappers raise the total complexity of the program just because they
contribute to the total lines of code (loc) count. Many people also think that
if you don't use these type-safe wrappers that your program will be doomed to
runtime errors.

I think both of these are big exaggerations, and that's why I wanted to write
that post. Even in spite of Go's generics situation (I'm not entirely
convinced about the degree to which it's a liability), I still find it to be
the most enabling tool in my bucket.

------
diakritikal
Sorry, but I can't see the value of posting this to hacker news. As evidenced
by many people in this thread assuming it's from one of the core Go
development team, it's not.

~~~
ominous_prime
Exactly. This is one person's attempt to distill the previous conversations
down to one document. It's not supposed to be justifying or rationalizing
anything, nor does it speak for the core language contributors!

It's one person's summary of a very long and convoluted conversation. That's
all.

------
donatj
To be fair I've not worked much in a languages that support generics but I
assure you there are type safe solutions to most every problem without them
(as long as you don't write yourself into a corner). Whether my life could be
simpler using them is unseen but to say the lack of them cripples a language
is wholly untrue. You're simply used to using them in your solution and are
wired to think with them. That's a flaw in the developer, a lack of
imagination, not a flaw in the language. Arguing every language needs every
feature every other language has is stupid. "[lang1] is bad because it isn't
[lang2]" Is always an infuriatingly stupid and pointless argument. Use lang2
if you love it so much. Seriously.

~~~
coldtea
That we can manually hack around this with busywork and tiptoe around the
issue with various hacks doesn't mean it's not a flaw in the language.

It's 2014. Generics are a settled deal in programming languages. It's not some
syntactic sugar or something the value of which is stull undecided and its
advocates might "lack an imagination".

> _Use lang2 if you love it so much. Seriously._

Well, some do. That doesn't mean they don't get to complain about something
they perceive broken in Go that could be better. Especially if they could use
Go (to take advantage of other benefits it might have) if it weren't for those
shortcomings.

In general, the statement is analogous to "if you have a problem with X in
america, why don't you immigrate", which is silly. If you have a problem, you
criticize, and you try to change that. You don't just dismiss everything
that's also not problematic.

------
crawshaw
For those who have not been following this discussion, I suggest reading this
comment by Ian:

[https://groups.google.com/d/msg/golang-
nuts/smT_0BhHfBs/MWwG...](https://groups.google.com/d/msg/golang-
nuts/smT_0BhHfBs/MWwGlB-n40kJ)

~~~
pjmlp
Thanks for the link, Ian's comment is very interesting and goes into the
direction I was stating in another post.

------
jcadam
As a language, I like Go. I would like it to have generics (Ada-style generic
syntax might fit best). I don't care enough to get emotional about it. So,
meh.

------
JulianMorrison
Given "go generate", I actually think that code generation might be better.
It's a more fussy mechanism, yes - but it's also a lot more general.

~~~
masklinn
1\. Any old-timer Windows developer will tell you that statically generated
code still has to be understood and maintained.

2\. generics are about type-safety, not codegen. Codegen can be added on top
of parametric polymorphism (e.g. C++ template specialisation), but is not
required by any means (C# or Rust don't do any generic-based codegen beyond
reification)

------
wheaties
If they give us type safe c-like macros I will happily live without generics.
This is from a Scala dev. I write Go because it's easier and less error prone
than going through JNI. However the lack of any reasonable abstractions in Go
makes it my last choice language.

------
robmccoll
Let's just use the C++ approach. Maybe with more restrictions to prevent
abuse. Maybe not. To me the problems with C++ templates arise from their
verbosity (Go's type system is rigid, but defining types is easy and
encouraged and the compiler does inference for variable declarations), their
abuse (let's keep it to simple type insertion), and the nasty errors /
debugging (Go's type system rigidity should also help here).

Just being able to do very light type insertion and the transparent code
generation to go along with it would go a long way.

------
tomp
Does anyone know how generics (for maps, slices, channels) are implemented
currently in Go? Does it use type-specialization or boxing approach?

------
pcl
_(The Java approach.) Box everything implicitly._

Boxing and generics are orthogonal concepts.

Also: does auto-boxing even make sense in Go? Between the fact that Go is
statically compiled and that there isn't an int / java.lang.Integer dichotomy
to resolve, I would assume that the compiler could just do whatever it needed
to with primitives, regardless of generics.

~~~
masklinn
> Also: does auto-boxing even make sense in Go?

Yes, and already happens: interfaces cause wrapping of their content[0] and go
does basic escape analysis and automatically allocates things which escape a
function on the heap rather than the stack[1]

[0]
[https://golang.org/doc/faq#nil_error](https://golang.org/doc/faq#nil_error)

[1]
[https://golang.org/doc/faq#stack_or_heap](https://golang.org/doc/faq#stack_or_heap)

------
gnuvince
The cons subsections that say that a generic version can be less optimized
than a concrete version should mention which implementation is considered. If
you use mono-morphization, then you end up with the same code as you would
have written by hand, so there is no loss of performance there.

~~~
egonelbre
Abstract things are harder to optimize than concrete things. A package for a
concrete problem can be more optimized than a generic/abstract package.

I don't mean that the manually specialized version is faster than
automatically specialized template. Rather that this encourages to not write
abstract data-types, but rather concrete types that solve a real world problem
- editor.Buffer vs. gap.Buffer. Once you have a real world problem it can
optimized much better for that use case.

------
karavelov
I was considering Go for some project of mine but the lack of generics turned
me away because the project needed to do some heavy numeric computations over
custom containers (sparse matrices).

Now days I think that adding generics to Go will be disaster - Go lacks sound
type system and piling generics on top of it will make the thinks even worse.

------
willvarfar
In the pros for generic data-structures, it doesn't mention type-safety?!?!

------
howeyc
I'm at the point where I hope they never add them, even though I've liked them
in other languages.

Once they do, you know not every "generics or bust" will be satisfied and the
anti-Go hate will simply shift.

I say let the haters hate and keep generics as their focal point.

~~~
pmr_
So, you argue to not add a feature to the language because it would fix one of
the main points of criticism? That is silly, don't you think?

~~~
sigzero
It is. The Go language devs should just own it and say "No". Will the
arguments shift somewhere else? Maybe but maybe the "Go needs generics" folks
will just go away.

~~~
coldtea
> _The Go language devs should just own it and say "No"_

Which is the grown up, honest, thing to do.

But I'm not sure about the other thing you mention:

"Maybe but maybe the "Go needs generics" folks will just go away."

Why would they go away?

They ask for Generics because they have found some use for Go (say, because it
has a OK standard library, or decent tooling and momentum compared to
alternatives), but also found a need this feature.

Neither the "use of Go" they found, nor their need for generics will disappear
if the language devs say "no". If anything, as stakeholders in the languge (a
user is a stakeholder) they'd be even more pressed to change the language
dev's mind -- down to the fork point.

~~~
anjanb
How many years to go before go users/developers outside of google will fork
"go lang" the way node.js users/developers did ?

the go-lang team at google is very smart. It's not that they have a huge
amount of high-priority work other than generics. Why don't they address a
summary of the sentiment on hacker news on generics ?

~~~
coldtea
If you're a programmer, your life is made easier if you have access to
generics.

If you're a language developer, your life is made harder if you have to add
generics.

And if your language gets all the people that are easily satisfied with
something "static and faster to write than C" why go the extra mile?

Especially if your goal is not building a commercially succesful language, or
an advanced language, or a language to solve 2014's problems, but just to hack
on what you have created.

Besides, being a great programmer and a great language designer are two
different skills. Would a language created by Linus be that good?

------
abroncs
Not trying to troll, but it's seriously depressing how much time is wasted on
this language.

~~~
robmccoll
Trolling or not, comment is unproductive. Might I suggest offering
alternatives such as rehashing the "rust is arguably a better design with
similar goals" vs "rust's library isn't as complete and the language isn't
stable" debate?

I have been writing Go code professionally nearly every day for 6 months.
Would I rather be writing C? Probably. Python? Not on a project of this scale.
C++? Toss up. Java? No - doing far to much interfacing to C libs for that.
Rust? Probably. Go is far from perfect, but honestly not that bad.

~~~
codygman
What advantages does Go have over Erlang?

~~~
sacado2
It can be learned by a programmer knowing only imperative C-family languages
in a couple of hours, meaning I can hire any average developer and make him
productive in less than a week. Not the same as teaching pure functional style
with pattern-matching and prolog's syntax. Go is also much more efficient. It
also produces static executables and can be easier to deploy -- or not,
depending on the exact situation. It handles strings nicely -- anything other
than Erlang's approach to strings is nice.

Erlang has other advantages, though. 99.9999999% uptime and hot code
replacement are easier with it, for instance. Their ideal niches don't
completely overlap.

~~~
codygman
I believe I can agree to the above statements.

------
p0nce
More FUD and rationalizations from GhettoLang!

> do you want slow programmers, slow compilers and bloated binaries, or slow
> execution times?

Easy I want "slow compilers and bloated binaries".

In my experience "bloated binaries" in the real world aren't as bad as one
would think, since instruction cache problems only appear when your _working
set_ is huge, not when your _total binary size_ is huge.

Equating big binaries with slowness is simply misleading. What's next,
increased download times?

> The generic structures are less useful than a concrete one.

Without generics you can't separate algorithms from data structures so
everything is much less useful. If the members names are worse, sub-type then
rename symbols.

> Generic structures can be less optimized than a concrete solution.

False. That "concrete solution" not only has to be written, but it will also
perform identically to an instantiated template.

And type erasure is not a solution, it prevents inlining, constant folding and
hoisting. Eg: In C++ std::vector<MyObject>::operator[] has 1 indirection,
while using a generic C void* container would have 2. Guess which one is
faster?

> Generic algorithms can be less optimized than a concrete solution.

 _sigh_

Also wrong since generics do not prevent specialization if needed. See: static
if in D, template specialization in C++.

~~~
egonelbre
> Without generics you can't separate algorithms from data structures so
> everything is much less useful.

Generics is not the only way to separate data and algorithms. I agree that it
is possible to sub-type/embed and rename - although looking at generic code, I
rarely see that happen.

> That "concrete solution" not only has to be written, but it will also
> perform identically to an instantiated template.

When you know where exactly the code will be run, it can be possible to create
a better package taking into account the context where it will be run. By
concrete, I mean a package in a real-world problem.

Basically, abstract things are harder to optimize for a particular case.

~~~
p0nce
> Generics is not the only way to separate data and algorithms.

Do you see any way other than the 3 ones discussed in the OP article under the
label "Generics"?

> When you know where exactly the code will be run, it can be possible to
> create a better package taking into account the context where it will be
> run. By concrete, I mean a package in a real-world problem. Basically,
> abstract things are harder to optimize for a particular case.

I could agree with that if time wasn't limited, but imho building custom data
structure/algorithms for each problem will precisely leave less time to
optimize for performance since reaching a working state first will be longer
without reusable abstractions.

~~~
egonelbre
> Do you see any way other than the 3 ones discussed in the OP article under
> the label "Generics"?

The one I mainly meant was interfaces. Of course there are also DSLs and code
generation.

> I could agree with that if time wasn't limited, but imho building custom
> data structure/algorithms for each problem will precisely leave less time to
> optimize for performance since reaching a working state first will be longer
> without reusable abstractions.

I mentioned that in the summary. It's about tradeoffs. Even if all the
cons/pros are listed people could still come to different conclusions, because
people value different things. And there's nothing wrong about it.

The amount you need to reimplement depends on the amount of available third-
party packages - the more good packages there are the less you need to build
those custom data structures.

