Personally, I prefer the current interfaces-based solution to generics. It's a little verbose, but keeps the language simple.
However, I think that the people we should be listening most are the ones developing huge projects in Go, like Kubernetes. Would having generics with this new contracts thing make it easier to develop and maintain e.g. Kubernetes? I'm truly curious.
It is a hack. The article lists a whole series of things that are standard in other languages that you can't do in go. Here are some examples:
Find smallest/largest element in slice
Find average/standard deviation of slice
Compute union/intersection of maps
Find shortest path in node/edge graph
Apply transformation function to slice/map, returning new slice/map
And here are data structures that other languages have but go does not:
Sets
Self-balancing trees, with efficient insertion and traversal in sorted order
Multimaps, with multiple instances of a key
Concurrent hash maps, supporting parallel insertions and lookups with no single lock
If it were not a hack, then go would not have these limitations.
Many smaller projects would benefit too. I would like to build a typesafe tree for an efficient sorted map, and to be able mergsort over multiple trees of different types. It would allow some extremely useful channel combinators for doing rather common things like safely shutting down a service with some background processing. Often these things leak and a often I find myself spawning more go routines just to map between types or to stop generic interface types infecting the rest of the API.
I have been vigorously pro-generics since the beginning, and this is the reason why: I want generic data structures. Arrays&slices and maps are great, and they really are the 90/10 solution a lot of the time, which is precisely why putting direct support into your syntax for the two of them is so very, very popular, but that other 10 comes up.
Plus, there are some generic data structures that will really work well in Go, like, for instance, an immutable tree. Granted, it'll still take some care to use properly in Go as it does not have "const" or anything like it, but it can still be done. The problem I have is not with accidental mutation, but that I just don't want to sit there and implement the immutable tree code. (Trees are great, but they're really tedious to write in the best of times, and nightmares to debug in the worst.)
I'm not terribly interested in trying to jam functional programming into Go; I may make light use of map/filter/reduce but even if this was fully implemented it would still be a fairly unpleasant experience (function that return "a value and an error" aren't much fun to map and can't hardly "chain" at all). But I've missed being able to just grab a particular data structure a few times.
Oh dear. Personal attacks are not ok on HN, regardless of whom you're attacking. Please stick to the site guidelines, no matter how passionately you feel about the Liskov Substitution Principle.
It’s fairly difficult to come to terms with an “everything was going pretty well until...” moment and doubly so when it can be personified.
Once we broke LSP, a cascade of similar ideas started showing up with regularity, especially in J2EE. I used to be able to go on at some length but now it’s more “I hope I never meet this guy because it’ll be awkward as hell.”
> The only truly unforgiveable one is UnsupportedOperationException. The guy who wrote the collections API for Java didn't know the first thing about the Liskov Substitution Principle, and gave the world an implementation that violates it...
The implementation perfectly follows it because the LSP simply requires identical behavior, and the contract clearly states it may[1] throw an exception. All the implementations "may" throw an exception. Sorry, but they correctly lawyered the LSP.
> I came up with around 20% more than the selected design.
But `add` can throw 5 different exceptions depending on restrictions your implementation wants to place on a given collection, does it allow for all that? In terms of making an interface that was small and reusable by many projects, runtime exceptions are a pretty good compromise for a standard library.
Yes, those are the same behavior. Both of them "may" accept it and "may" reject it, and "may" includes both "always" and "never".
It is correct to the letter of LSP, but not the spirit of it, and this was a conscious decision; contrary to your original claim, they understood the principle perfectly well.
Of course they do. Not sure why it’s something to brag about or not to brag about though, it’s an implementation detail. Scala for instance uses custom classes for each size set up to a certain threshold.
Kubernetes is a transpiled Java project, so yeah, Java-like features would definitely make it easier :P
I think idiomatic golang works pretty well without generics in most cases, the big problem for me is that functional programming is essentially impossible without them.
It was originally written in Java and lots of its Go code is a strange mix of the two (Java-like idioms in Go). This might be where the term "Gova" came from.
If you read the article more closely, it says that Borg was written in C++. If you watch the video linked by @tuvan below, you'll hear the speaker (who is a contributor) mention that the original authors of Kubernetes wrote the first version in Java, which was rewritten in Go.
Agreed on keeping the status quo, adding generics makes it really easy to write bad code and increases mental overhead. Simplicity is what we should be going for, not having generics should've been kept as a selling point.
This may be practical from the point of view of 'top level applications' in Go. But there is a lot of murk in pure Go implementations of databases, and datastructure heavy libraries that could be avoided and lead to better testing and less duplication. If you find it simpler to avoid generics that ought to be possible under this design.
However, I think that the people we should be listening most are the ones developing huge projects in Go, like Kubernetes. Would having generics with this new contracts thing make it easier to develop and maintain e.g. Kubernetes? I'm truly curious.