back

by dmit·9y ago·view on hn ↗
If you follow the history of that particular issue, you'll see that the Go team's (official) view has always been that there are tradeoffs involved, and that none of the existing proposals for implementing generics are sufficient improvements over the status quo. Generics are not free, they bring a lot of baggage with them. And I think most people will agree that Go has achieved a lot of success without them, so perhaps most use cases don't require generics after all.
7 comments
>If you follow the history of that particular issue, you'll see that the Go team's (official) view has always been that there are tradeoffs involved

Only everybody who asks for generics knows that, and still wants them to go through and pay the price.

The "we'll only add them when there's a solution with no tradeoffs" is a red-herring, like "we'll add them on a day that doesn't end in -y".

>And I think most people will agree that Go has achieved a lot of success without them, so perhaps most use cases don't require generics after all.

In the same sense C has achieved quite a lot with buffer overflows, so what's the point in something like Rust?

>Only everybody who asks for generics knows that, and still wants them to go through and pay the price.

And those people are outnumbered by people who are comfortable and productive with the current Go implementation.

Programming languages are not all placed on a single Bad<---->Good scale. There are many variables involved, and it makes sense to have local maxima like Java, Go, Clojure, C, Haskell, etc.

> And those people are outnumbered by people who are comfortable and productive with the current Go implementation.

Citation needed. How do we know that the majority of Go users would prefer not to have generics? How do we know the number of non-Go users would be willing to use Go if it had generics is insignificant? Is there some large scale survey of Go users somewhere you can cite?

>And those people are outnumbered by people who are comfortable and productive with the current Go implementation.

The only way to know that would be to be able to compare one implementation with and one without generics. But only one Go implementation exists. Perhaps there's some toy attempt by someone, but not anything that is equal in all other aspects to mainland Go but with Generics on top.

Plus, since most of the burden falls on the compiler writers and most of the benefits to end users, it just takes the compiler writers to be "comfortable with the current Go implementation" for this to continue to remain Generic-less.

Here's a question for you: what if the Go team add user-defined generic types to the language, and people start demanding HKTs? What then? Do you implement them and hope nobody asks for dependent types? Where do you draw the line?
The Slippery Slope is also a fallacy, and this exemplifies why.

Java didn't have generics. Then they didn't have lambdas. Now they're even redoing the classpath! Have they gone nuts?

No, they've been evolving, and they've kept on adding features as it was opportune and useful to do so. If tomorrow's programming paradigms depend on HKTs and dependent types, then, yes, Go might want to add them. Today's programmers are just about starting to understand what a dependent type even is, so you're suggesting to include them in Go in order to ridicule the potential inclusion of generics. This is a fallacy, because generics and dependent types are years, decades, apart. And generics are very much part of how several generations of programmers have learned, and expect to be able to program.

If your language stops changing, your language is already dead. Yet another point of similarity between natural and programming languages.

I didn't mean to ridicule anything. My point is that there are multiple evolution vectors for programming languages, and generics->HKT->DT->? is just one of them. It's quite possible that in the foreseeable future the biggest winnings might come from tooling/libraries/ecosystem rather than the type system. (Of course, those are mostly orthogonal.)
Well, it's a soristic problem, but there are some clear heuristics:

1) tons of people have asked for Generics, few have asked for HKTs.

2) C++, C# and Java, programming languages with millions of users and extremely battle tested have Generics, no mainstream language at that level offers HKTs.

3) As a result of (2) a ton more people are familiar with Generics than HKTs, and so the latter are much less probable to be requested.

And of course, if they do add Generics, and people ask for HKTs, they should consider what they do about that then and there, not now.

No reason to never make a step towards somewhere just because you might (or will) be asked to also take a further one.

Except if they believe that they are already at some optimal point (which is my case I think).

What about all those people who came to Go from Python, JavaScript, Ruby and whatnot? They are mostly content with the current status quo, generics would just make the learning cliff steeper for them. And according to the Go devs, more people come to Go from Python than from, say, C++. So perhaps it makes sense to stay at that level, at least for now?

All I'm saying is this doesn't seems like a simple equation to me. There are many possible solutions to the problem of building large, correct, maintainable, performant programs - and neither of the existing ones looks like a surefire winner given all the limitations.

People who came to Go from Python, JavaScript, and Ruby will likely have had a steepish learning curve getting used to pointers in Go. I hadn't used pointers since programming in C++ in 1995 when I switched to Go, and it took a bit of time to get used to remembering that extra detail.

In fact, because I used Clojure just before switching to Go, I found not having immutable variables harder to get into the habit of more than anything else. I actually first used Go because I needed to write something that manipulated bits in memory reliably, and couldn't be bothered going back to Java.

Indeed, not many developers have moved from C++ to Go, though there are a few from Java who might miss generics. Here is some recent data on this:

https://golangnews.com/stories/1490-results-of-the-gopher-la...

> What about all those people who came to Go from Python, JavaScript, Ruby and whatnot? They are mostly content with the current status quo,

As a counter-example, I'm not sure this is true.

The argument works against any language feature, not just generics.

As a aside, why not add HKTs straight with generics? The problem the Go implementors have with generics seem to be about run-time representation (boxing or unboxed), but no additional run-time issues arise from HKTs. The main issues of HKTs are that type inference becomes harder. Haskell's approach of eschewing type-inference at the kind level (because it's undeciable anyway) but giving unkinded type variables the kind * seems to be a run-away success.

> What then?

Irrelevant. Go already has parametric functions like append, it just doesn't allow user defined ones. append isn't enough when a programmer needs to remembers 10+ tricks to make up for the lack of generics :

https://github.com/golang/go/wiki/SliceTricks

> And those people are outnumbered by people who are comfortable and productive with the current Go implementation.

Of course they are. The people who are not comfortable with the current implementation aren't using Go.

It's a fallacy to only look at what the major users wants. It's similar to the “faster horses” fallacy.

> Of course they are. The people who are not comfortable with the current implementation aren't using Go.

Not true. What about those who write Go at work for instance?

Of course, but there is a set of people who would be willing to use Go for new projects, but are not doing so because of this and other reasons.
> The "we'll only add them when there's a solution with no tradeoffs" is a red-herring, like "we'll add them on a day that doesn't end in -y".

Russ actually addressed this at length: https://news.ycombinator.com/item?id=9622417

How is that comment anything but a refusal to move on unless some magic tradeoff free solution appears? It even ends saying that "Programming language researchers are sometimes disappointed that Go hasn’t picked up more of the recent ideas from the literature, but those ideas simply haven’t had time to pass through the filter of practical experience. I believe generics is one of those ideas.".

But Generics are neither some new PL topic, nor have they not passed the "filter of practical experience" (millions use them in C++, Java and C# alone).

I'd rather they explicitly said: "It will take a total breakthrough in computer science regarding generics implementations for us to consider them for Go, and we wont ever care of paying the costs of any current, viable in practice for millions of programmers in other mainstream languages, approach".

> How is that comment anything but a refusal to move on unless some magic tradeoff free solution appears?

Well I (somewhat) agree with that, but my take of it was Russ is basically saying existing approaches "don't work well with Go" and "recent ideas" are "not well understood" with the concern that "there's a princess in another castle after that one I am sure."

Or put it another way, per his emphasis on the "engineering" nature of Go, it is not an issue of tradeoffs, rather a concern that a runaway train of complexity will follow. Or if you will excuse my Mexican French, the problem is the fucken type system :)

> How is that comment anything but a refusal to move on unless some magic tradeoff free solution appears?

A programming language design is the combination of a set of features. The hard part in designing a language is working out how all these features interact with each other.

For example, one feature of Go is that every type has a default value (0 for decimals, nil for pointers, empty string for strings, etc.). This property leads to the inability to include algebraic data types cleanly. To see this, consider this simple ADT (in Haskell syntax):

  data Either a b = Left a | Right b
What's the default type here? It could be "Left(default-value-of-a)" or "Right(default-value-of-b)". You could introduce additional syntax to define the default value, but that increases complexity. You could introduce a rule how the default value is inferred in these cases, but that goes against the Rule of Least Surprise. You could remove the "default value for every type" feature that clashes with ADTs, but that causes problems elsewhere. Therefore Golang lacks ADTs and uses pointers and multiple return values instead.
How is it that array and map are generic, then?
> Go has achieved a lot of success without them

This is a dangerous and slippery slope to engage on.

Java was also extremely successful in 2004, before it supported generics. Yet you'd be hard pressed to find a Java developer who thinks that generics were not overwhelmingly beneficial to the language, and probably one of the main reasons why Java is even more dominant and powerful today than it was pre-generics.

I have been a Java developer since the JDK alpha in 1995. It was apparent then that Java was going to be pretty big due to the fact it was VM-based, addressed a lot of pain points like platform independence/concurrency/interfaces/etc., and was similar enough to C/C++ that people would adapt to it quickly. The language experienced an enormous network effect due to the tooling and support libraries that allowed Java to become dominant in enterprise development.

It's hard to argue that a feature that appeared a decade later changed the equation all that much. I like generics but would still use Java even if they did not exist. In my work the concurrency features are far more important.

Buyin and successful are not necessarily the same thing.

Designers of Go have been disciplined enough to keep things simple - let's you keep more of the problem domain you're trying to solve, along with the code to solve it, in your head. Try that with a big project using another toolchain - lots of frameworks, lots of places to plug your code, with less coherency (in my experience) across the various experience levels of your team. And I'm talking about big teams here, not 10 devs.

Subjective Success metric with comparable teams: Go vs <x with generics>. If Go team gets solution done faster, correct, within budget compared to other team, your stakeholders will not give a crap about what devs think about generics. There's a good chance that would happen, based on my experience.

Well, except that some of us do remember Java 4 fondly. It was a much simpler language and that was quite a good thing. I'd say "overwhelmingly beneficial" is an exaggeration.
For my purpose generics in Java are not overwhelmingly useful. I work on a quite big and successful, Java application inside our company. And it was written mostly after Java 1.5 but hardly use much of generics. It may have many issues but none related to generic.

I am not saying generic are not useful. But I have not found enormous use of Generics in typical Java business application. The most common generic data structure I have used in Java are Maps and lists which are already generic in Go.

I think you are underestimating the indirect effect that generics have had on your code, even if you don't use them directly yourself.

Thanks to generics, millions of lines of code in libraries that you are using became safer and faster, and you are benefiting from this, even if it's not apparent to you.

Basically, generics made Java a better and safer language. Both theoretically and practically.

Generics for a language with a common base class object are a category error.

Java's current popularity is due to Android, not the bloated corpse of enterprise Java.

Types like Object and Comparable<T> allow heterogeneous collections and algorithms, which are occasionally useful even in an otherwise statically-typed language. Think of it as a set of types where otherwise you would have required boxing everything within a single type and eventually reimplementing the type system.

If Java had generics from day one, they could have put methods like equals and hashCode in interfaces that some classes don't implement, instead of passing static type checks and then blowing up at runtime because you did something that never made sense.

Java has been in the top three most popular languages since the early 2000s.

Android certainly made it more popular than it already was, but Java was extremely popular way before Android appeared.

Modern languages like Rust and D are being designed with generics and people are supposedly paying some prime for that complexity. I wonder if anyone using generics in their language would give them up for some increase in performance or language simplicity. It's doubtful.

Internally, the Go team has drawn up proposals for adding generics [1] but rejected them because of drawbacks. Hopefully one day we can see those drawbacks, because maybe a lot of us are more than happy to pay that price.

[1] https://www.reddit.com/r/golang/comments/46bd5h/ama_we_are_t...

> Hopefully one day we can see those drawbacks, because maybe a lot of us are more than happy to pay that price.

Why wait for "one day"? These proposals are public: https://github.com/golang/proposal/blob/master/design/15292-...

Rust without generics would not work well. (FWIW, I consider Go quite usable and enjoy using it.) The reason is that Rust very much depends on building up safe abstractions around data structures with unsafe implementations. Without generics, folks would need to re-implement those data structures and `unsafe` would become profligate, which diminishes Rust's core value proposition.

    Hopefully one day we can see those drawbacks
One of the main issues with Go is that we can't see those discussions. With C++, C, Rust, D, Java those proposals are public from Start to Finish.

From the discussions I've seen on what Go considers complicated I'd bet it work out to be something like name mangling.

Go turns off ASLR for loaded C code because its easier to debug. Which is really only true if your debugging process requires memorizing the absolute address of symbols that control flow will jump too. I guess that is useful if you are reading the raw hex streams.

Name Mangling is complicating things because you can no-longer debug with ElfRead.

Go seems to reject anything that was invented after the ~70's. As those concepts are complicated.

I can't help but feel that Thompson and Pike just don't want to change the bad habits they've developed from by-gone ages and adopt modern tooling.

> If you follow the history of that particular issue, you'll see that the Go team's (official) view has always been that there are tradeoffs involved, and that none of the existing proposals for implementing generics are sufficient improvements over the status quo

They should have thought about it at the very beginning of Go design. it's easy to say now "We didn't find a good way to implement generics" when their design choices made implementing generics insanely hard at first place.

Well actually,they thought about it, where does append,delete,make and co come from? how do these functions know their arguments and return types at compile time? generics.

Furthermore it's not all or nothing. Go could have supported parametric functions in user land just like append,make or delete without implementing full-on generics. They just don't want to bother with that, because it's impossible to retrofit generics now without breaking the reflect package. The rest is just excuses to evade the issue.

> Generics are not free

Creating a modern statically typed language WITHOUT generics isn't free either. Just like implicit interfaces are not free, just like the reflect package is not free, just like using interface{} somewhere isn't free, just like telling people to use code generators isn't free.

I thought the special pass given to append, make, and delete depends on the special nature of slices and maps.

That is, a []Whatever is not as opaque as a Whatever{} or an interface{}. Same with a map[Foo]Bar, you (you being Go) know it's a map.

(I have no opinion on whether Go should have generics, I just think the apparent exceptions make sense even if they might seem unfair.)

Your argument doesn't explain why a programmer cannot implement his own append or delete functions on existing container types. These exceptions do not make sense.
How many years has it been and they still haven't come up with anything?

Go doesn't have generics because they don't want them.

That's just not true, there are not tradeoffs that aren't solved multiple decades ago. Go implementors are lazy and dogmatic.
This discussion of generics and the tradeoffs doesn't strike me as either lazy or dogmatic. Have you read it?

https://github.com/golang/proposal/blob/master/design/15292-...

Yes. It's absurd. Dogmatic isn't a great word to describe it but how can you live in 2016 and not read it as lazy?
The argument is more along the lines of "the upsides of Generics are known, and the downsides are that many of our users will find them confusing". That pretty much says what you need to know about the language.