Watching Go's development is like reliving the development of Java (which also didn't have generics at first), but over decades instead of years. Cannot wait for Go to implement an error handling system in the 2030s.
This is great. Will be useful for data access methods!
As for the detractors, from the first generics proposal this was called out as a "not now", not never. There were questions of implementation. They aren't a super large team, and they try to do things incrementally and do them well.
This resolves a big gap in generics for most people coming from other languages to go so I completely approve this direction. Not saying use it everywhere but if you must use it, it’s better to have it on the struct than call a module level generic func.
It's (sadly) still not possible to express monads with this change, since generic methods can't implement interfaces. You'd probably want something like:
type Monad[T any] interface {
Bind[U any](func(T) Monad[U])
}
However this requires the Bind method to be generic, which still isn't allowed in an interface
> Go doesn't support such generic interface methods because we don't know how to implement (calls of) them, or at least we don't know how to implement them efficiently.
I don't really understand this argument. I read the discussion linked to[1], and yeah, monomorphization approaches (whether at compile time, link time, or runtime with JIT) are obviously going to be difficult or impossible, but the reason against using runtime reflection is mostly that it's slow. But that runtime reflection is exactly how you would work around it today.
For the Identity example, could the interface be compiled to be basically equivalent to:
Identity(any) any
and then at the callsite add a cast of the return type to T?
I suppose primative non-pointer types add a bit of a wrinkle but even if it generic methods was restricted to pointer types, that's better than nothing. And the number of those types is relatively small, so when the implementation is compiled it could just instantiate method implementations for all the primative types, if they apply, and then maybe remove them if they aren't needed at link time.
Of course it's also possible there is some detail I've missed.
Watch as this gets rejected for nonsensical reasons just like the issue about adding uint128, which also has been open for an extremely long time and they keep moving the goalposts as to reasons why it can't be done...
Since they can't implement interfaces, Generic methods are just syntax sugar for generic functions. I'm surprised they actually accepted this proposal for sugar.
I remember lack of generics being pitched as a feature of Go initially, not a lack. The original design goal was simplicity. I don’t use Go, so have no opinion on this, just interesting that it’s going in this direction.
I wrote Go professionally for years. I don't know how many hours I've spent debugging and reviewing nil pointer bugs and race conditions. Generics were sorely needed but the initial implementation was lacking.
I moved to Rust professionally 4 years ago and haven't looked back. Mutex<T> Option<T> Result<T, Err> are all phenomenal.
I've written everything from web backends, frontends (hurry up wasm, seriously), to Node.js and Python extensions.
Web backends use under 1mb of memory and can support hundreds of thousands of concurrent users on a $2/m VPS. Frontends can be beautifully multithreaded. Native extensions can dance between OS threads and multi-threaded runtimes.
When I review code I focus only on the logic, not sidetracked by reasoning about race conditions or anything. Great when you review the work of less experienced contributors.
The ultra strict compiler is extremely helpful with LLMs. You bounce back and forth until it compiles and, if it compiles, it's usually correct.
It's at the point where I can't really see a use case for another language - and yet, no one uses it! It's madness!
And so the cycle will continue. Always a shame when languages cave like this and add extra unnecessary complexity and error prone hard to parse syntax.
It'll be interesting to see the next language that comes along rejecting bloat in favor of simplicity, and then we can all start again.
26 comments
[ 2.9 ms ] story [ 48.5 ms ] threadI respect that.
As for the detractors, from the first generics proposal this was called out as a "not now", not never. There were questions of implementation. They aren't a super large team, and they try to do things incrementally and do them well.
I don't really understand this argument. I read the discussion linked to[1], and yeah, monomorphization approaches (whether at compile time, link time, or runtime with JIT) are obviously going to be difficult or impossible, but the reason against using runtime reflection is mostly that it's slow. But that runtime reflection is exactly how you would work around it today.
For the Identity example, could the interface be compiled to be basically equivalent to:
Identity(any) any
and then at the callsite add a cast of the return type to T?
I suppose primative non-pointer types add a bit of a wrinkle but even if it generic methods was restricted to pointer types, that's better than nothing. And the number of those types is relatively small, so when the implementation is compiled it could just instantiate method implementations for all the primative types, if they apply, and then maybe remove them if they aren't needed at link time.
Of course it's also possible there is some detail I've missed.
[1]: https://go.googlesource.com/proposal/+/refs/heads/master/des...
It is Apple's school of design, think different, ah, actually, there are reasons why the fence is in the middle of nowhere.
Then the design ends up half way there versus being done properly from the beginning.
nah I'm kidding
<after 55 seconds>
Seriously, what's wrong with `#define`?
I moved to Rust professionally 4 years ago and haven't looked back. Mutex<T> Option<T> Result<T, Err> are all phenomenal.
I've written everything from web backends, frontends (hurry up wasm, seriously), to Node.js and Python extensions.
Web backends use under 1mb of memory and can support hundreds of thousands of concurrent users on a $2/m VPS. Frontends can be beautifully multithreaded. Native extensions can dance between OS threads and multi-threaded runtimes.
When I review code I focus only on the logic, not sidetracked by reasoning about race conditions or anything. Great when you review the work of less experienced contributors.
The ultra strict compiler is extremely helpful with LLMs. You bounce back and forth until it compiles and, if it compiles, it's usually correct.
It's at the point where I can't really see a use case for another language - and yet, no one uses it! It's madness!
It'll be interesting to see the next language that comes along rejecting bloat in favor of simplicity, and then we can all start again.