I wrote up a coherent proposal based on the core of the idea below, and added it to the feedback wiki:
https://gist.github.com/rcoreilly/bfbee2add03c76ada82810423d81e53d Overall I think it seems quite promising as perhaps the most “Go” version of generics possible, which solves the major use-cases, while retaining essentially the same existing syntax and just adding a few additional keywords. I can’t see any major limitations other than those intrinsic to the idea itself (e.g., you can’t define a Min function that works across any type whatsoever), and I don’t think it introduces any violations of existing static type safety. Curious to hear what others think! Cheers, - Randy > On May 31, 2019, at 4:28 PM, Randall O'Reilly <rcoreil...@gmail.com> wrote: > > This seems similar to previous proposals based on introducing kind-based type > categories for contracts. Putting the kind right there in the arg instead of > a separate contract seems like an improvement, keeping it more local to where > it is used. Why not just take this one step further and just introduce > entirely new types: > > * number > * slice > * map (re-useable from existing use-case?) > * etc > > func Min(x, y number) number { > if x < y { > return x > } > return y > } > > func Delete(sl *slice, idx int) { > *sl = append((*sl)[:idx], (*sl)[idx+1:]) > } > > The compiler would just do its normal thing based on whatever actual kind you > pass in — an implicit type switch basically.. > > You could convert any `number` into a specific type (e.g., float64) when you > need to, and if you passed two different underlying types of numbers as args > to Min, it would automatically up-convert to the one with highest precision. > Essentially, this is undoing all the strict type specificity of Go, and > making it work like C, or Python.. > > This minimalist approach avoids all the complexity and ugliness of > parameterizing types etc — it is just a more generic type of type, and is > more or less how the generic builtin operators and functions like len, copy, > etc already work on their respective kinds. > > Composite types seem like they might even just work without a type parameter: > > type Vec2 struct { > X, Y number > } > > func (u Vec2) Add(v Vec2) Vec2 { > return Vec2{u.X + v.X, u.Y + u.Y} > } > > In summary, this is really just introducing a very controlled dose of dynamic > typing into the language (adding a dash of Python into Go). Probably this > has already been considered and rejected hundreds of times over the course of > these discussions, but I’ve lost track, and seems at least like a very simple > conceptual proposal: you can achieve a lot of generics functionality by just > introducing dynamic typing. Syntactically and conceptually, it is far > cleaner and simpler than anything else I’ve seen in the generics discussion, > at least. > > - Randy > >> On May 31, 2019, at 6:52 AM, Michal Strba <faiface2...@gmail.com> wrote: >> >> @Ian, I have been thinking and I’ve come up with a possible solution to >> yours and some other problems. I’d love to hear your thoughts on it. Note, >> that this is a very fresh idea. >> >> I’m addressing two problems here: >> >> • Inability to do Min/Max and other generic numeric functions. >> • There are a few kinds of generic parameters, but the kind is always >> implicit. This can be a problem because changing the body of a function can >> result in a backward-incompatible change, even when the signature remains >> the same. >> Here are the ideas (also described in the proposal now, in the section >> called ‘Further ideas’). >> >> The kind of a generic parameters is currently completely implicit. Some >> annotation could be added. One possible syntax could be like this: >> >> • gen n for generic array lengths. >> • gen T for arbitrary types (convertible to interface{}). >> • gen eq T for equalable types (comparable with == and usable as map >> keys). >> • gen num T for numeric types (with operators like +, -, <, …). >> Array lengths and arbitrary types can have the same notation because it’s >> always possible to distinguish them by context. Alternatively, they could be >> distinguished by capitalization (lower-case for array lengths, upper-case >> for types). >> >> Syntax-wise, eq and num would not be keywords on their own. Rather, gen eq >> and gen num would be two-word keywords. >> >> The syntax is rather ad-hoc, I admit. It’s a very fresh idea, completely >> open to refinement. However, since there are only four cases, an ad-hoc >> syntax may actually be the right choice. >> >> It’s also easily extensible with new possible “contracts”, but I’d generally >> advise against that. >> >> The addition of the num restriction would actually enable many cool things. >> First, the Min/Max functions: >> >> func >> Min(x, y gen num T) T { >> >> if >> x < y { >> >> return >> x >> } >> >> return >> y >> } >> >> It would also be useful for generic math types, like vector and matrices. >> The matrix example above uses float64, but it could be generalized to all >> numeric types. >> >> As an example, let’s take a look at a possible implementation of a 2D vector >> type: >> >> type Vec2(T) struct >> { >> X, Y T >> } >> >> There are no restrictions specified in the type definition. This is because >> it’s methods and functions that require restrictions, not the types >> themselves. For example, this String method requires no restrictions: >> >> func (u Vec2(gen T)) String() string >> { >> >> return fmt.Sprintf("(%v, %v)" >> , u.X, u.Y) >> } >> >> This Eq method requires the types to be comparable with ==: >> >> func (u Vec2(gen eq T)) Eq(v Vec2(T)) bool >> { >> >> return >> u.X == v.X && u.Y == v.Y >> } >> >> But, this Add method requires the types to be numeric: >> >> func >> (u Vec2(gen num T)) Add(v Vec2(T)) Vec2(T) { >> >> return >> Vec2(T){u.X+v.X, u.Y+v.Y} >> } >> >> Consequently, Vec2([]float64) would only have the String method, >> Vec2(string) would have the Eq method in addition, and Vec2(float64), >> Vec2(int32), and so on, would have all the methods. >> >> Yes, the idea basically is to introduce two "contracts" into the system. >> However, there's no ability to create own contracts and the syntax is very >> concise and non-disruptive. I believe this would really cover the vast >> majority of use-cases. >> >> >> pi 31. 5. 2019 o 14:05 <fge...@gmail.com> napísal(a): >> On 5/31/19, Nick Keets <nick.ke...@gmail.com> wrote: >> ... >>> This proposal is very interesting and seems to fit nicely into Go, with >>> minimal disruption. And speaking personally, it would cover 99% of my needs >>> for generics (I'm not that interested in Min/Max, but writing functions to >>> get map keys gets old fast). >> Interesting, could you please share the problems where the usual >> iterating idiom is not good enough? >> >> -- >> You received this message because you are subscribed to the Google Groups >> "golang-nuts" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to golang-nuts+unsubscr...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/golang-nuts/CA%2Bctqro9o-RAa6QRVCEQ%2BPu_tre%2BCtJQZaP4LbBTB_6LQntWyg%40mail.gmail.com. >> For more options, visit https://groups.google.com/d/optout. >> >> -- >> You received this message because you are subscribed to the Google Groups >> "golang-nuts" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to golang-nuts+unsubscr...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/golang-nuts/CAO6k0usrzSrh1j-xboqtxh8jJCz0eRDpfvTggfgi-0%3D10XhNoA%40mail.gmail.com. >> For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/EC3BD38A-48A0-4EBA-AE8D-54445D51C0CB%40gmail.com. For more options, visit https://groups.google.com/d/optout.