I like the second draft for generics. It seems to me a large simplification and improvement over the first draft. Considering just the state of Go today, I would be quite happy with this, even if it's not perfect. Thanks to Ian, Robert, and everyone else for their work on this.
Also, I would vote for square brackets over parentheses. But I do have concerns related to the future development of Go. In particular, if we think it likely that a future version of Go will allow operator overloading, then perhaps type lists are not the best choice. To my mind, the biggest defect in the design draft is that we can't write generic functions and types that work transparently with both builtin and user-defined types (that do not inherit appropriate behavior from an underlying builtin type). For example, we can't write a func Min[type T ...](a, b T) T { ... } that works both when T is int and when T is type BigInt struct { i *big.Int } Instead, we would use workarounds such as writing two versions of Min, or passing in an adaptor function or object; in the case of Min, a comparison function. And that's OK, especially in an initial version of generics. But generics would be significantly easier to use if we could write functions that work on both builtin and user-defined types. The two most likely candidates for allowing this seem to be operator overloading (where BigInt might have a method named "<", "operator<", or some such, that allows it to be used with the < operator) and methods on builtin types (where int might be given a method named Less with the same behavior as the < operator). Of course, other solutions could be imagined, but I'll confine my speculations to those two. Now let's try to imagine how sorting slices might be implemented in the standard library in various futures. Of course, the current sort package would have to be kept and maintained for a long time. If Go2 implements the current draft with type lists, then we might add a sort2 package containing something to: func SliceBy[type T](s []T, less(T, T) bool) { ... } type Ordered interface { // Copied from the draft type int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, string } func Slice(type T Ordered)(s []T) { SliceBy(s, func(a, b T) bool { return a < b }) } type Lesser[type T] interface { Less(T) bool } func SliceByLess(type T Lesser[T])(s []T) { SliceBy(s, T.Less) } All well and good. Now say time goes by and Go3 adds operator methods. Nothing in the sort2 package expresses a unified sort using operator methods, so we need a new package sort3: func SliceBy[type T](s []T, less(T, T) bool) { ... } type Lesser[type T] interface { <(T) bool } // Or whatever the syntax is. func Slice(type T Lesser)(s []T) { SliceBy(s, func(a, b T) bool { return a < b }) } (We might just add sort3.Lesser and sort3.Slice into the sort2 package under different names, but I suspect the aim would be to eventually deprecate sort2.) The effects will ripple through other code, both in and outside the standard library. Suppose some Go2 code has a chain of generic functions A calls B calls C calls D, where each exists in two versions, one for builtin types and one for user-defined types, and the two versions of D call sort2.Slice or sort2.SliceByLess. When Go3 with operator methods arrives, if we want to unify these, we have to write a third version of each of A, B, C, and D, where D calls sort3.Slice. On the other hand, suppose Go2 has type lists and Go3 gives builtin types methods corresponding to operators. Assuming the name Less is used for <, sort2.SliceByLess now handles both builtin and user-defined types, so we don't need a sort3 package. And in the ABCD scenario, we can just keep the SliceByLess version of each, and quietly let the sort2.Slice versions vanish as they become unused. [Important point===>] This means that if Go2 has type lists in interfaces, there will be a strong incentive for Go3 to give builtin types methods, even if we think that operator overloading is otherwise a superior solution, because operator overloading will require much more new code to be written. Instead of using type lists, suppose Go2 allowed interfaces to require the presence of specific operators. Then the sort2 header might look like this: func SliceBy[type T](s []T, less(T, T) bool) { ... } type Lesser[type T] interface { <(T) bool } func Slice(type T Lesser)(s []T) { SliceBy(s, func(a, b T) bool { return a < b }) } type MLesser[type T] interface { Less(T) bool } func SliceM(type T MLesser[T])(s []T) { SliceBy(s, T.Less) } (Note that the first part is identical to the previous sort3 header. But in Go2 we also need MLesser and SliceM in order to handle user-defined types.) This leaves us more easy options in Go3. If Go3 implements operator overloading, then sort2.Slice now handles both builtin and user-defined types, and code using sort2.SliceM can be allowed to wither away. If Go3 implements an int.Less method, then sort2.SliceM is now the good version, and code using sort2.Slice can be allowed to wither away as it becomes unused. So maybe the alternative of allowing interfaces to require specific operators deserves another look, to see if it's really not viable in Go2. I would suggest that perhaps the initial version of generics need not support all operators; maybe it's enough to support only those that apply to numeric types (string should be accepted by interfaces requiring +, <, and other comparison operators). Or maybe a slightly larger subset of operators would do. As a final note - this post, like all speculations about the future, is rather fuzzy. I realize that. Nevertheless, I think it is important to realize that the choices we make now carry consequences for our options after a few years' time. -- 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/CAADvV_stjEvD4pLwGNmahAEzc0UDNLuzwttZ9wDg78BOJfDA5Q%40mail.gmail.com.