> My point is that if Go is not going to have a story for templated types, then we need to own it, just like Haskell programmers own their decisions.
> 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).
so, they're asking people who didn't use go because of generics to provide experience reports on the specific kind of problems they encountered when writing go ???
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.
They are asking people who extensively use Go to help collecting cases where generics would be useful in the context of real world Go programs. So instead of cargo-culting a random generics design from a different language or some theoretical reasoning, they want to make sure to enhance the language in a way that actually solve real-world problems in programs written in Go.
> Wouldn't it imply that they're happy with the current audience of the language, and don't wish to extend it ?
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.
well not really. I'm saying it could be interesting to ask people that decided not to use go , the reason they choose not to, in order to expand their user base.
> well not really. I'm saying it could be interesting to ask people that decided not to use go
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.
I use Go quite a lot, and I agree with their "irrational arguments". It seems quite dishonest to pretend that anyone who doesn't use Go because they found it too restrictive to be "wasting their time with irrational stances". It's also quite close-minded.
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.
To offer a counter point: I dislike the idea of "I write generic code". I say this because it is one of the prime calling-cards of the over-abstraction, which IMO is one of the biggest (and most harmful) self-inflicted injuries in programming right now.
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.
I'm not going to speak for the whole Go community, but most people I've talked to in the community has eventually agreed that a lack of generics make code harder to write (after giving them some examples and showing them how other languages made this problem much simpler). That wiki page is quite a bad way of asking for feedback for two reasons:
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 actuall...
Because you should stop asking for generics like in Java/C#/rust etc..
Such generic to make custom type safe container is like using a canon to kill a fly.
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.
i'm sorry, what in my post made you think i wouldn't be happy with your solution ?
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).
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.
If it can be implemented without significantly affecting pre-existing code, I see no reason why not. Generics are infinitely preferable to VerbBytes(), VerbString(), VerbFloat(), ...
one annoying thing about go error handling aside from the copious `if err != nil` statements is that if someone somewhere doesn't handle an error there's no way to find! yes I know about errorcheck or whatever that library is called but I think it's silly you'd leave something like that up to a library.
With generics, it would be possible to write a library implementing 2-track, functional error handling, which would allow for a form of automatic error propagation. The if err != nil statements would be kept to a minimum. It's precisely the lack of generics in the first place that makes error handling in Go so obnoxious.
Java and C++ programmers seem to like generics (templates in C++'s). Both languages needed to make some compromises, like Java's run-time type erasure and the complexity of the C++ templates with the resulting compile times.
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.
C# generics don't have either of those issues, though there's no C# wildcard type, which means annoying workarounds through inheritance when you want a list of wildcard generics.
"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."
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.
It's important to remember how simple Java was in 1999. 10-15 years from now it's likely Go will have all the features that people have been asking for. The earlier these features are added the better. As a project gets larger it gets much harder to make large changes. Do it now and while they're at it they should fix the lack of good exception handling and a few other things that they will most likely have to address eventually.
> 10-15 years from now it's likely Go will have all the features that people have been asking for.
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.
It's interesting that it's 2017 and this question still gets asked. Go having static types but no generics is the worst of two worlds: both dynamic languages and compiled languages with genetics have basic functional constructs like map/reduce but Go insists on sprinkling interface {} everywhere and calls this "solution" good enough?
https://godoc.org/golang.org/x/sync/syncmap leaps to mind as a type whose users should demand and get static type safety, but it can't happen until the language definition adds yet another special case blessing it as a properly supported collection type.
I wonder if Go could avoid full genetics by supporting union types, as seen in languages like Ceylon and TypeScript.
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.
There's no amount of union types that will save you if you want to write a polymorphic, type safe map/filter/reduce function. These functions need to be generic over containers.
At best, with this union type hack what you'll recover is similar to "ad hoc" polymorphism, not true parametric polymorphism.
TypeScript has support for union types and generics because they aren't interchangeable. The purpose of generics is to avoid having to duplicate code or list every possible type as an input.
This isn't like inheritance because there are already generics in Go; in all the built-in collections and channels. By releasing the very first version the designers admitted that generics are necessary.
Hmmm, on one hand Golang/generics seems to be a fairly popular discussion issue on (at least) HN.
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. :(
43 comments
[ 0.88 ms ] story [ 126 ms ] thread> 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:
https://github.com/golang/go/wiki/ExperienceReports
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 actuall...
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.
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?
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:
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.
So, this basically would boil down to something like C++ templates, with he extra requirement that templates must be instantiated explicitly.
https://github.com/ncw/gotemplate
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.
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.
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.
Any libraries or anything in particular?
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:
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.
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. :(