Andrew Bonventre | fde42b6 | 2018-08-28 09:56:58 -0600 | [diff] [blame] | 1 | # Go 2 Generics Feedback |
| 2 | |
| 3 | This page is meant to collect and organize feedback about the Go 2 [contracts (generics) draft design](https://go.googlesource.com/proposal/+/master/design/go2draft-generics-overview.md). |
| 4 | |
| 5 | Please post feedback on your blog, Medium, GitHub Gists, mailing lists, Google Docs, etc. And then please link it here. |
| 6 | |
| 7 | As the amount of feedback grows, please feel free to organize this page by specific kind of feedback. |
| 8 | |
Liam | c066212 | 2018-08-28 22:33:12 -0700 | [diff] [blame] | 9 | - Liam Breck, “[Please Don't Mangle the Function Signature](https://gist.github.com/networkimprov/7c1f311f26852bc912765e4110af062b)”, August 2018 |
| 10 | |
DeedleFake | 1de3684 | 2018-08-29 02:05:40 -0400 | [diff] [blame] | 11 | - DeedleFake, "[Feedback for Go 2 Design Drafts](https://deedlefake.com/2018/08/feedback-for-go-2-design-drafts/)", August 2018 |
| 12 | |
Roberto | 94c8e9a | 2018-08-29 13:59:07 +0200 | [diff] [blame] | 13 | - Roberto (empijei) Clapis, "[Hard to read syntax](https://gist.github.com/empijei/a9665ac5e3059671be229acee8826798)", August 2018 |
Roberto | f76be04 | 2018-08-29 11:20:54 +0200 | [diff] [blame] | 14 | |
Richard Fliam | 3fbbd81 | 2018-08-29 17:42:29 -0600 | [diff] [blame] | 15 | - Richard Fliam, "[Go2 Generics Let You Construct the Natural Numbers](https://gist.github.com/rfliam/c806a4300aa97f2762295ef97d3e924f)", August 2018 |
| 16 | |
emilymaier | 230baa9 | 2018-08-30 00:23:20 -0400 | [diff] [blame] | 17 | - Emily Maier, "[Getting specific about generics](https://emilymaier.net/words/getting-specific-about-generics/)", August 2018 |
| 18 | |
Roger Peppe | 13c0fdd | 2018-08-30 11:01:20 +0100 | [diff] [blame] | 19 | - Roger Peppe, "[Go generics feedback](https://gist.github.com/rogpeppe/2be10112c9d875afc0c85effc5595a09), August 2018 |
| 20 | |
Liam | 6d4eebc | 2018-08-28 22:29:09 -0700 | [diff] [blame] | 21 | - _Your Name_, “[_Title_](#URL)”, _month year_ |
| 22 | |
Andrew Bonventre | fde42b6 | 2018-08-28 09:56:58 -0600 | [diff] [blame] | 23 | - etc. |
Dag Sverre Seljebotn | 3841f01 | 2018-08-28 21:07:53 +0200 | [diff] [blame] | 24 | |
| 25 | |
| 26 | ## Quick comments |
| 27 | |
Bodie | 6307b68 | 2018-08-29 11:52:44 -0400 | [diff] [blame] | 28 | - [Bodie Solomon](https://github.com/binary132): I find the generics design a bit confusing and opaque. Please consider integrating some concepts from [Zig's beautiful comptime functions](https://news.ycombinator.com/item?id=13761571)! The design of Go 2 generics is clever, but I feel it goes against Go's traditional tight coupling between simple runtime semantics and simple syntax. Additionally, one of the biggest problems of Go, which prevents it from being a viable competitor everywhere I might like to use it, is that I cannot be rid of the GC and runtime. It was my strong hope that Go 2 would introduce compile-time-only generics such that I could reliably avoid the use of dynamic interfaces where I don't want them, without relying on codegen. Unfortunately it looks like that will be decided by the compiler without my input. Please, at least, consider giving users the ability to constrain generics to compile-time-only resolution, perhaps as a property of a Contract, rejecting compilation of dynamic types to satisfy the contract. |
| 29 | |
Maxwell Corbin | 9144ad3 | 2018-08-28 12:58:11 -0700 | [diff] [blame] | 30 | - Dag Sverre Seljebotn: C++ has a huge problem with people abusing metaprogramming ("generics") to do compile-time metaprogramming. I really wished Go had gone down the path of Julia, which offers hygienic macros. Even if it is kept strictly at a compile-time barrier and no run-time code generation, this would at least avoid all the bad tendencies we see in the C++ world that comes from their templating system. Things you can do with generics you can usually pull off with macros too (e.g., `SortSliceOfInts = MakeSliceSorterFunctionMacro!(int)` could generate a new function to sort a slice of integers). Link: https://docs.julialang.org/en/v0.6.1/manual/metaprogramming/ |
| 31 | |
| 32 | - Maxwell Corbin: The issues raised in the Discussion and Open Questions section all could be avoided by defining generics at the package rather than the function or type level. The reason for this is simple: types can reference themselves, but packages can't import themselves, and while there are many ways to algorithmically generate more type signatures, you cannot do the same with import statements. A quick example of such syntax might be: |
Takuma Ishikawa | 4e952c2 | 2018-08-29 13:37:30 +0900 | [diff] [blame] | 33 | |
| 34 | ```go |
| 35 | \\ list |
| 36 | package list[T] |
| 37 | |
| 38 | type T interface{} |
| 39 | |
| 40 | type List struct { |
| 41 | Val T |
| 42 | Next *List |
| 43 | } |
| 44 | |
| 45 | // main |
| 46 | package main |
| 47 | |
| 48 | import ( |
| 49 | il "list"[int] |
| 50 | sl "list"[string] |
| 51 | ) |
| 52 | |
| 53 | var iList = il.List{3} |
| 54 | var sList = sl.List{"hello"} |
| 55 | |
| 56 | // etc... |
| 57 | ``` |
| 58 | |
| 59 | The syntax in the example is probably needlessly verbose, but the point is that none of the unfortunate code examples from the blog post are even legal constructions. Package level generics avoids the most abusive problems of meta-programming while retaining the bulk of its usefulness. |
Maxwell Corbin | 9144ad3 | 2018-08-28 12:58:11 -0700 | [diff] [blame] | 60 | |
Russell Johnston | 31d1271 | 2018-08-28 20:51:02 -0700 | [diff] [blame] | 61 | - Andrew Gwozdziewycz: The use of the word `contract` gives me pause due to it overloading "contract" as in [Design by Contract](https://en.wikipedia.org/wiki/Design_by_contract). While the generics use case has some similarities with the "contracts" in DbC if you squint a bit, the concepts are quite different. Since "contracts" are an established concept in Computer Science, I think it would be far less confusing to use a different name like `behavior` or `trait`. The design document also suggests reasons why using `interface` is not ideal, though, Go's contract mechanism seems too obvious an extension of interfaces to disregard so quickly... If it can be done `interface setter(x T) { x.Set(string) error }` and `interface addable(x T, y U) { x + y }` seem quite natural to read and understand. |
| 62 | |
Hajime Hoshi | f82716f | 2018-08-29 12:58:25 +0900 | [diff] [blame] | 63 | - Russell Johnston: Agreed that it would be great to merge contracts and interfaces. Another way around the operator-naming problem might be to provide some standard interfaces for the operators, with bodies inexpressible in normal Go code. For example, a standard `Multipliable` interface would allow the `*` and `*=` operators, while a standard `Comparable` interface would allow `==`, `!=`, `<`, `<=`, `>=`, and `>`. To express operators with multiple types, these interfaces would presumably need type parameters themselves, for example: `type Multipliable(s Self /* this exists implicitly on all interfaces */, t Other) interface { /* provided by the language */ }`. Then user-written interfaces/contracts could use these standard identifier-based names, neatly sidestepping the issues mentioned in the design document around syntax and types. |
Roberto | 6059b20 | 2018-08-29 14:57:35 +0200 | [diff] [blame] | 64 | - Roberto (empijei) Clapis: I agree on this and on the fact that it should be clearer where to use interfaces and where to use contracts. Unifying the two would be great, as they try to address overlapping issues. |
Kurnia D Win | a72b7e3 | 2018-08-29 22:53:33 +0700 | [diff] [blame] | 65 | - Kurnia D Win: I think `constraint` is better keyword than `contract`. Personally i like `type addable constraint(x T, y U) { x + y }` instead of merging with interface. |
Hajime Hoshi | f82716f | 2018-08-29 12:58:25 +0900 | [diff] [blame] | 66 | |
Hajime Hoshi | 5297861 | 2018-08-29 13:01:29 +0900 | [diff] [blame] | 67 | - Hajime Hoshi: I feel like the supposed proposal is too huge to the problems we want to solve listed at https://go.googlesource.com/proposal/+/master/design/go2draft-generics-overview.md . I'm worried this feature would be abused and degrade readability of code. Sorry if I am missing, but the proposal doesn't say anything about `go generate`. Wouldn't `go generate` be enough to the problems? |
Stephen Rowles | c831c58 | 2018-08-29 11:45:23 +0100 | [diff] [blame] | 68 | |
| 69 | - Stephen Rowles: I find the method syntax hard to parse, as a human reading it, it might be clearer to use a different type of enclosing brackets for the type section, e.g. |
| 70 | |
Stephen Rowles | bb46989 | 2018-08-29 11:45:49 +0100 | [diff] [blame] | 71 | ``` |
| 72 | func Sum<type T Addable>(x []T) T { |
| 73 | var total T |
| 74 | for _, v := range x { |
| 75 | total += v |
| 76 | } |
| 77 | return total |
| 78 | } |
Roberto | c46f169 | 2018-08-29 13:55:11 +0200 | [diff] [blame] | 79 | ``` |
Roberto | 6059b20 | 2018-08-29 14:57:35 +0200 | [diff] [blame] | 80 | - Roberto Clapis: Please read [this section](https://go.googlesource.com/proposal/+/master/design/go2draft-contracts.md#why-not-use-like-c_and-java) |
Roberto | 5e630f6 | 2018-08-29 14:59:34 +0200 | [diff] [blame] | 81 | - Seems like a bit of a cop-out tbh. It says "in general" which means there must already be exceptions. Go has a nice clear syntax making code simple to read and easy for teams to collaborate. I think it would be worth making the parser more complicated for the sake of making the code readability better. For large scale and long running project readability of the code, and hence maintainability, is king |
seebs | 12d6f0f | 2018-08-29 10:18:29 -0500 | [diff] [blame] | 82 | - What about [this](https://gist.github.com/empijei/a9665ac5e3059671be229acee8826798) |
| 83 | |
sean-q | f6bb2fc | 2018-08-29 17:24:48 -0700 | [diff] [blame] | 84 | - Seebs: [Feedback a bit long to inline](https://gist.github.com/seebs/8f943b8b15a8c63c28c7f6f4e5ca6c53), August 2018. Summary basically "I would like a way to specify one contract for each of two types rather than one contract for both types", and "I would prefer `map[T1]T2` to `t1var == t1var` as a canonical form of "T1 must be an allowable map key". |
| 85 | |
sean-q | 1b50aad | 2018-08-29 21:07:17 -0700 | [diff] [blame] | 86 | - Sean Quinlan: I find the contract syntax quite confusing. For something that is supposed to defined exactly what is needed and will be part of the documentation of an api, it can contain all sorts of cruft that does not impact the contract. Moreover, to quote from the design: "We don’t need to explain the meaning of every statement that can appear in a contract body". That seems like the opposite of what I would want from a contract. The fact one can copy the body of a function into a contract and have it work seems like a bug to me, not a feature. Personally, I would much prefer a model that unifies interfaces and contracts. Interfaces feel much closer to what I would like a contract to look like and there is a lot of overlap. It seems probable that many contracts will also be interfaces? |
Nodir Turakulov | 4e84f17 | 2018-08-29 20:33:51 -0700 | [diff] [blame] | 87 | |
Nodir Turakulov | e87d766 | 2018-08-30 07:43:41 -0700 | [diff] [blame^] | 88 | - Nodir Turakulov: Please elaborate |
Nodir Turakulov | 4e84f17 | 2018-08-29 20:33:51 -0700 | [diff] [blame] | 89 | > Packages like container/list and container/ring, and types like sync.Map, will be updated to be compile-time type-safe. |
| 90 | |
| 91 | and |
| 92 | |
| 93 | > The math package will be extended to provide a set of simple standard algorithms for all numeric types, such as the ever popular Min and Max functions. |
| 94 | |
Nodir Turakulov | e87d766 | 2018-08-30 07:43:41 -0700 | [diff] [blame^] | 95 | or ideally add a section about transition/migration of existing types/funcs to use type polymorphism. |
Nodir Turakulov | f855db2 | 2018-08-30 00:57:32 -0700 | [diff] [blame] | 96 | FWIU adding type parameter(s) to an existing type/func most likely breaks an existing program that uses the type/func. |
| 97 | How exactly will `math.Max` be changed? |
Nodir Turakulov | 4e84f17 | 2018-08-29 20:33:51 -0700 | [diff] [blame] | 98 | Is the intention to make backward-incompatible changes and write tools to automatically convert code to Go2? |
| 99 | What is the general recommendation for authors of other libraries that provide funcs and types that currently operate with `interface{}`? |
Nodir Turakulov | f855db2 | 2018-08-30 00:57:32 -0700 | [diff] [blame] | 100 | Were default values for type parameters considered? e.g. type parameter for `math.Max` would default to `float64` and type parameter for `"container/list".List` would default to `interface{}` |