Should Go 2.0 support generics?
dave.cheney.net
dave.cheney.net
For example, you could declare a function as Foo(thing string | []int). In other to use "thing" you'd need to do a type assertion. That'd allow "generic" functions where the author could decide which types to support, without going all the way to generics, which tend to open a few cans of worms. Same thing for structs and such. Obviously this has an impact on internal layouts; union values would need an internal type tag similar to interfaces.
With this in mind, I would hope that Go could get better pattern matching with destructuring; switch statements currently only allow you to extract one value, and it's confusing that a single name is shared between all cases. But I'd love to be able to do something like:
switch thing {
case s := string:
...
case [x, y] := []int if len(thing) == 2:
...
}
or whatever.If we could get proper Rust-style enums on top of that (with appropriate pattern matching) that'd also be neat.
At best, with this union type hack what you'll recover is similar to "ad hoc" polymorphism, not true parametric polymorphism.
> This isn’t simply a case of saying “nope, sorry, no generics for Go 2.0, maybe in another 5 years”, but a more fundamental statement that they are not something that will be implemented in Go because we believe there is a better way to solve the underlying problem.
ffs. tldr; yes. Add generics.
Come on, the feedback from the community has been overwhelming.
If we were going to 'own' not having generics, we wouldn't be having this conversation.
There's a disconnect here, clearly, between the community and what the community wants, and what the language makers and designers want.
I think what Dave is advocating here is basically the 'status quo' from golang 1.0 (ie. we'll never have generics).
That hasn't worked.
Lets not do it again.
It can be hard to tell, which is why they came up with a process and are asking for experience reports:
I write or use generic code in every single of my projects. i don't need to start coding in go ( which i did) to understand what i'll miss. i did my share of void* casting in C and i know how much it sucks.
This is an old problem. Everybody knows what the use is and what the benefits are. They tried to show the world that they were wrong and they failed to convince that people could get away without this feature. Now all they need is to get over it and start implementing something to fill that gap.
nothing wrong with that, though.
You're assuming that people who have some degree of interest in generics and aren't Go users right now will somehow and for some reason decide to avoid Go just because it lacks generics.
It's a silly assumption.
You're assuming that these people have anything relevant to say, particularly as they present irrational arguments to justify their fatwa on a programming language.
Meanwhile, those who are interested in exploring the language and are interested in putting it to work aren't wasting their time with irrational stances on a minor technical detail.
You're right that most Go developers aren't going to go out of their way to write a 5-page dissertation about how generics would help solve a problem they worked around, but that's not a justification for not including generics. The fact you have to write orders of magnitude more code in order to work around a lack of generics is ridiculous, and I find it frustrating every time I have to do it. Will I eventually crack and write a series of blog posts that just rant about every single fucking problem I have with Go? Maybe. But it seems quite unreasonable to only want reviews which effectively must be of the form of a coherent rant.
Honestly, IMO, 9 times out of 10 the places that developers use templated-types in order to "write generic code", it is an over-abstraction. The generics end up adding nothing but source-code complexity. I often wonder if the only reason generics get used in some situations is because the standard lib uses them.
1. It ignores the fact that most people who encounter a language problem will rather just work around it and make uglier code "because they have to" than to write a several-page dissertation on why generics would've solved their problem. Heck, some programmers haven't used generics before and don't realise that your code can become much simpler if you use them correctly. When I first found out that I could define a trait on a generic container type in Rust, I was massively surprised and realised how much unnecessary Go code I'd written recently because this one feature was missing.
2. It assumes that the programmers who complained about all of these issues in Go 1.0 several years ago are still sticking around, and can be bothered to reiterate the same arguments they made all that time ago (and were ignored all that time ago). Asking for more comments may sound like a "nice thing to do", but if you already burned the goodwill of the larger programming community with similar stalling tactics, then people are going to be less likely to be willing to help again.
I will give you some examples that have personally bitten me. The most frustrating part is that Go _does_ have generics, except that they are restricted to only be used by builtin types. make, new, len, cap, etc are all generic functions for the builtin collection types. But here are some examples:
1. Collection types are effectively impossible to implement usefully. []T will not be promoted to []I if T is a type that implements an interface I. This requires creating a new slice in memory and doing a noop cast (the same applies to arrays and maps). As a result, creating a generic sort implementation won't work. Yes, Go has a "sort implementation"[1] but rather than requiring something like []Ordinal you have have the _slice type_ implement Swap and Compare. Just look at how bare the container package is (and note that they require you to implement all of the core features of the container yourself). In a language with generics such as Rust (or even Java) this interface would be considered ridiculous, but in Go it's the only way of giving some kind of generic functionality (even though it's not actually generic in any sense of the word -- you have to implement all of the common code manually even if it is structurally identical).
2. Everything that wants to be generic in some sense devolves into using interface{} to represent "something that I will use reflection to introspect". However, the reflection API is far from good, and there are cases where because there is an interface{} type in the way, you cannot mutate something that you would be able to mutate if you didn't have define things as interface{} (an *interface{} doesn't allow you to modify the underlying type through reflection as far as I could tell). Admittedly, I have done some very dodgy stuff with Go's reflection API, but that doesn't mean it's a good API.
3. The workarounds for generics have reached the point where some people created tools that generate code that implements a "generic type" by manually generating the code for each type. This is something that compilers for languages that have generics do _automatically_, but in the Go universe you have people so desperate for generics that they are re-implementing something that should be a compiler feature as part of their build pipeline. I personally don't use any of those tools, because after trying several of them I realised that they make your code even harder to understand because all of the type information is generated in a way that obscures what you're actually trying to do.
The only reason I write Go code is because (for some misguided and other justified-at-the-time reasons), the majority of the container ecosystem is written in Go and it's not reasonable to switch to anything else. A bunch of other developers and I have been looking at switching over to Rust, but there is a lot of inertia in keeping everything in one language. But if you saw what fairly horrific shit Kubernetes had to do in order to emulate generics with reflection, you would likely want to run for the hills.
[1]: https://golang.org/pkg/sort/ [2]: https://golang.org/pkg/container/
I'd like user defined collections to be easier in go, but that's only one reason I'd like generics in go. I'd also like to remove one of the biggest arguing points over the programming language go, a language I think hits lots of important requirements. Getting it adopted by more teams will be easier and the whole go ecosystem will expand more rapidly if there was less to argue over.
I believe the go team when they say they haven't solved all the problems with adding generics to go; however, worse is better and Java and C++ show that an approach to generics doesn't have to be perfect to be very beneficial.
That's how I feel about it. I have a suspicion that this will play out like classes in ES6: some people use them a lot, some don't, some feel that that they should not be used, but it was necessary to add them to the language for the community to move forward.
Any libraries or anything in particular?
On the other hand, it's weird (to me) that people seem to seriously be considering Golang 2.0, when the current (1.0) doesn't even have debugging working 100%.
Debugging on Linux with non-CGO seems ok. All other situations though have various levels of breakage. :(
I stopped because of the error handling. try in rust/scala is just too awesome to go back to basically a tuple that will always need to be handled.
What is so hard to understand in that need ??
You should ask for generic package/templated package. It solve the problem, it's way simpler and and would only touch a small part of the spec. More importantly, it wouldn't change the way we code in go today.
With generic package you only have to define the parameter in package declaration like this:
package list {Value: interface{}
And use it by importing it like this:
import list "container/list" {Value: int}
And that's why to go team asked for use case. To use the most simple tool to fix a problem so there is less chance for other problems to appear. If every people wanting to make custom type safe container would stop asking for full generics and instead would brought their case with a simpler solution. I'm sure it would have a chance to go in Go 2.0.
import list "container/list" {Value: int}
import list "container/list" {Value: string}
in a single source file. At the least, you would need the ability to give the type(s) that those import statements import distinctive names.Even that would, IMO, not be enough, as this seems (from what I infer the semantics to be) to make it impossible for writers of such a generic library to build on another generic library.
That can be fixed by allowing such a programmer to write:
package foo {MyValue: interface{}}
...
import list "container/list" {Value: MyValue}
but that, IMO, would be way too cumbersome. That package declaration would have to mention all types in all generic packages that get imported.I.e.
import intlist "container/list" {Value: int}
import stringlist "container/list" {Value: string}So, this basically would boil down to something like C++ templates, with he extra requirement that templates must be instantiated explicitly.
i would even be happy with no generic at all if basic types implemented low level interfaces, and let me code my containers against things like "sortable, equatable, hashable" ( although it may pose other problems).
A: I need a Ferrari to go to work. How is it hard to understand!
B: Well, you've only have 10 minute commute, a small car would do the work quite as well, as cost a lot less.
A: What made you think i wouldn't be happy with a smaller car?
If this hapoens, the entry bar will be high again. The tooling will get slow, and runtime will become more complex.
To me, Go is all about that simplicity that comes with the lack of features. Though I think it can probably provide a little more in terms of generics, it also has to be careful not to become Nim or D.