7 ms·
I love and continue to love how seriously the Go team takes breaking spec changes, as well as spec changes in general. Go generics are a bit of a blip in this
by liampulles 2y ago
I love and continue to love how seriously the Go team takes breaking spec changes, as well as spec changes in general.
Go generics are a bit of a blip in this to be honest, A) because it is a big change, and B) because it can be difficult to use (generic functions defined on types cannot use generic parameters that aren't defined on that type, for example).
But in a way, I also think the constraints help avoid the overuse of generics. I have seen Java and Typescript projects where developers had way too much fun playing around with the type system, and the resulting code is actually quite unclear.
In conclusion, I pray the Go team strive to and continue to be conservative with the language.
- VirusNewbie 2y ago>generic functions defined on types cannot use generic parameters that aren't defined on that type, for example This is bonkers to me, why???
- zeeboo 2y agohttps://go.dev/doc/faq#generic_methods https://go.dev/doc/faq#generic_methods
- singron 2y agoThis is a good write-up of the issue. To see where this craziness could have led, see the C++ overload resolution logic, which isn't the exact same problem but does smell the same: https://en.cppreference.com/w/cpp/language/overload_resolution https://en.cppreference.com/w/cpp/language/overload_resoluti...
- wseqyrku 2y agoI feel there's a clear alternative to the problem presented. I do not expect Empty to match any of those interfaces. A generic method should only match with a generic method of the same arity.
- int_19h 2y agoThis has nothing to do with arity?
- remexre 2y agoarity as in "number of generic arguments," I think they meant.
- int_19h 2y agoStill confused then, because there are two sets of generic arguments at play, and a proper call would match the arity of both.
- wseqyrku 2y agoYeah, it would be that plus the name and the signature as per usual. I don't think this is a huge limitation considering the alternative they chose: disallow generic methods altogether.
- int_19h 2y agoSo how would you implement generic method calls via an interface reference?
- VirusNewbie 2y agoThe same way the other languages do it.
- remexre 2y agoIsn't that way either JIT or boxed integers?
- maleldil 2y agoBecause they chose a half-assed way to implement generics, and the path they took doesn't interact well with the rest of the type system.
- jeremyjh 2y agoIs it clear they had any better choice after shipping 1.0 without generics?
- mcculley 2y agoNo. My recollection is a lot of people urging them to get generics right and into 1.0 and the Go guys saying, “don’t worry, we can add generics later”.
- yubblegum 2y agoNo, your recollection is not factual. Ross Cox laid out the case(s) and the fact that no option was manifestly preferable. Not sure what happened but after the initial resistance by the Gophers to ~1/2 of community clamoring for generics (I consider it a mistake) it seems some important Go based projects finally forced them to adopt one of the uglies (opinion, folks /g) https://research.swtch.com/generic https://research.swtch.com/generic
- pjmlp 2y agoThe same Ross Cox acknowledged that he was wrong. ". They are likely the two most difficult parts of any design for parametric polymorphism. In retrospect, we were biased too much by experience with C++ without concepts and Java generics. We would have been well-served to spend more time with CLU and C++ concepts earlier." https://go.googlesource.com/proposal/+/master/design/go2draft-generics-overview.md https://go.googlesource.com/proposal/+/master/design/go2draf...
- School-Cotton 2y ago“we were biased too much by experience with C++” (or C) could describe most of the dubious design decisions for Go. It seems there are tons of things the designers banned because they are bad in C, and didn’t supply any replacement because the C++ version is overly complicated or hard to use, and they weren’t aware of anything better. Metaprogramming is a perfect example. C macros are bad, C++ metaprogramming facilities are baroque, so let’s not have any metaprogramming features whatsoever and tell people to rely on code generations or reflection instead.
- xg15 2y agoJust to understand, methods cannot declare any new type parameters of their own, but they can use type parameters from the type they are bound to, can they?
- masklinn 2y agoYes.
- grandempire 2y agoThere isn’t a single language which has implemented genetics without those expanding to the complexity of C++ generics. It turns out most of the complexity is essential: - need overloading to support instantiation - need type functions/associated types. For example what type is inside this container? - need operator overloading so you can substitute generic types into assignment expressions. For example notions of equality. - need duck typing or traits to communicate capabilities The two simplifications which have historically worked are to use dynamic types, or to use code generators.
- VirusNewbie 2y agoSo the idea of type classes are so scary they went with shitty generics?
- grandempire 2y agoYes.
- rowanG077 2y agoIt depends on what you mean with generics. If it's only parametric polymorphism and ad hoc polymorphism then I would Haskell solves it trivially and very easy to understand. If you mean it to include full "template" metaprogramming or type level programming then I'm not sure.
- grandempire 2y agoIf go copies this design from Haskell would it look simple?
- rowanG077 2y agoSure. Type classes are extremely simple. Go generics are already superficially similar to type classes.
- 2y ago
- int_19h 2y agoFor the same reason why C++ doesn't have virtual function templates. The usual way to implement dynamically dispatched method calls efficiently is with vtables, but if your method is itself generic, and it can be dispatched through a superclass reference (or interface value in Go), how do you instantiate the implementation and allocate slots in vtable? C# can do this because it has a JIT and can compile such methods dynamically (and rejig vtable if needed). In an AOT-compiled language like Go, it would either need to treat this pessimistically and instantiate every possible implementation of every method that could be virtually dispatched anywhere in the program, or else it needs to do what Swift does and generate code that is generic at runtime - i.e. pass some kind of type descriptor with information like size of type and everything else that's needed to handle it, and then the code would look at that type descriptor and do the right thing; this works, but it's non-trivial, and generated code is very slow.
- lenkite 2y agoYet C++ is a very flexible language. You have the tools to implement approaches like "stateful metaprogramming" to give you virtual function templates if you really need them. There is nothing (wrt language) that cannot be done with C++.
- pjmlp 2y agoReflection, but it is finally being sorted out.
- neonsunset 2y agoJIT is not a requirement for this and 'GetFoo<T>().Bar<U>()` works just fine under NativeAOT (even if Foo is abstract and Bar is virtual). Indeed this involves expensive lookup for generic virtual methods. It is also not very friendly to NAOT's binary size once you start having many generic instantiations of the type with such method(s). In the case of Go, I'd assume it will require making both its VM and code reachability analysis more complex to make it work, and they decided to simply shift the responsibility and ceremony onto the programmer which is the standard in Go design.
- wruza 2y agoI wonder instead why it should feel extraordinary. Methods are tightly coupled with classes, so allowing more flex in a method should be non-free in a non-boring way. What reboot man mentioned comes to mind sort of immediately. How would you dispatch that and, more importantly, to hell with this kind of complexity anyway, even ignoring performance costs. It’s more of a swiss army footgun than a feature.
- chamomeal 2y agoI sorta agree. It can be ridiculously hard to understand and maintain other people’s complicate TS generics. But the payoff is that you have a type system that nearly disallows consumers of your interface to use it incorrectly. Like you’d never get the amazing type safety of libraries like prisma and kysely (an ORM and a query builder) if you couldn’t make such ridiculously expressive generics. But, only a teeny tiny subset of TS devs can work on generics that complex. I definitely can’t! It’s a tradeoff like anything else.
- ok_dad 2y agoWhat’s an example complex generic? If you have one, that is, I’m curious what kinds of things people do with types. I’m a fan of using types, myself. Thanks in advance.
- bobbylarrybobby 2y agoCheck out the implementations of axum’s Handler trait in Rust. https://docs.rs/axum/0.7.5/axum/handler/trait.Handler.html https://docs.rs/axum/0.7.5/axum/handler/trait.Handler.html
- foresterre 2y agoI sometimes see types in TS with complex generics like [1], but instead of being general like in this example, they're more specific to the type of their values. Couldn't find a proper example on the spot in an open source project. [1] https://github.com/sindresorhus/type-fest/blob/main/source/get.d.ts#L25 https://github.com/sindresorhus/type-fest/blob/main/source/g...
- chamomeal 2y agoHonestly any typescript library with great type safety probably has seriously gnarly generics inside. Here[1] is a random file from kysely, which is surprisingly readable even though kysely's type safety is incredibly good. But things I encounter in the regular non-library world are usually recursive types that have specific constraints. A couple years ago I had my first foray into typescript generics, and was so stumped that I actually gave up. I was trying to map the type of one nested object to another. This[2] is the stackoverflow post from the legendary jcalz that saved me! Check jcalz's link to the TS playground [1]https://github.com/kysely-org/kysely/blob/master/src/query-builder/output-interface.ts https://github.com/kysely-org/kysely/blob/master/src/query-b... [2]https://stackoverflow.com/questions/72461962/is-it-possible-to-recursively-map-one-json-like-type-to-another-in-typescript https://stackoverflow.com/questions/72461962/is-it-possible-...
- DeathArrow 2y ago>But in a way, I also think the constraints help avoid the overuse of generics. I have seen Java and Typescript projects where developers had way too much fun playing around with the type system, and the resulting code is actually quite unclear. Have you seen some C++ code where they make heavy use of templating?