blob: 9cb83ee44c641863a4570e0ac85452f491f9d35e [file] [log] [blame] [view]
Russ Cox00fd2f62018-08-23 15:11:30 -04001# Contracts — Draft Design
2
3Ian Lance Taylor\
4Robert Griesemer\
Ian Lance Taylorca869dd2019-07-31 10:30:47 -07005July 31, 2019
Russ Cox00fd2f62018-08-23 15:11:30 -04006
Ian Lance Taylore022bce2020-06-16 12:12:21 -07007## Superseded
8
9We will not be pursuing the approach outlined in this design draft.
Ian Lance Taylor78bd5252021-03-19 11:43:34 -070010It has been replaced by a [new
11proposal](https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md).
Ian Lance Taylore022bce2020-06-16 12:12:21 -070012This document exists for historical context.
13
Russ Cox00fd2f62018-08-23 15:11:30 -040014## Abstract
15
16We suggest extending the Go language to add optional type parameters
17to types and functions.
18Type parameters may be constrained by contracts: they may be used as
Ian Lance Taylor4a54a002019-07-26 23:21:48 -070019ordinary types that only support the operations permitted by the
Russ Cox00fd2f62018-08-23 15:11:30 -040020contracts.
21Type inference via a unification algorithm is supported to permit
22omitting type arguments from function calls in many cases.
23Depending on a detail, the design can be fully backward compatible
24with Go 1.
25
Russ Cox00fd2f62018-08-23 15:11:30 -040026## Background
27
Ian Lance Taylor4a54a002019-07-26 23:21:48 -070028This version of the design draft is similar to the one presented on
29August 27, 2018, except that the syntax of contracts is completely
30different.
31
Russ Cox00fd2f62018-08-23 15:11:30 -040032There have been many [requests to add additional support for generic
Ian Lance Taylor4a54a002019-07-26 23:21:48 -070033programming](https://github.com/golang/go/wiki/ExperienceReports#generics)
Russ Cox00fd2f62018-08-23 15:11:30 -040034in Go.
Andrew Bonventred41bf0f2019-07-29 16:25:31 -040035There has been extensive discussion on
36[the issue tracker](https://golang.org/issue/15292) and on
37[a living document](https://docs.google.com/document/d/1vrAy9gMpMoS3uaVphB32uVXX4pi-HnNjkMEgyAHX4N4/view).
Russ Cox00fd2f62018-08-23 15:11:30 -040038
39There have been several proposals for adding type parameters, which
Ian Lance Taylor4a54a002019-07-26 23:21:48 -070040can be found through the links above.
Russ Cox00fd2f62018-08-23 15:11:30 -040041Many of the ideas presented here have appeared before.
42The main new features described here are the syntax and the careful
43examination of contracts.
44
Ian Lance Taylor4a54a002019-07-26 23:21:48 -070045This design draft suggests extending the Go language to add a form of
Russ Cox00fd2f62018-08-23 15:11:30 -040046parametric polymorphism, where the type parameters are bounded not by
47a subtyping relationship but by explicitly defined structural
48constraints.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -070049Among other languages that support parameteric polymorphism this
50design is perhaps most similar to Ada, although the syntax is
Russ Cox00fd2f62018-08-23 15:11:30 -040051completely different.
Russ Cox00fd2f62018-08-23 15:11:30 -040052
53This design does not support template metaprogramming or any other
Ian Lance Taylor4a54a002019-07-26 23:21:48 -070054form of compile time programming.
Russ Cox00fd2f62018-08-23 15:11:30 -040055
56As the term _generic_ is widely used in the Go community, we will
57use it below as a shorthand to mean a function or type that takes type
58parameters.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -070059Don't confuse the term generic as used in this design with the same
Russ Cox00fd2f62018-08-23 15:11:30 -040060term in other languages like C++, C#, Java, or Rust; they have
Ian Lance Taylor4a54a002019-07-26 23:21:48 -070061similarities but are not the same.
Russ Cox00fd2f62018-08-23 15:11:30 -040062
63## Design
64
65We will describe the complete design in stages based on examples.
66
67### Type parameters
68
69Generic code is code that is written using types that will be
70specified later.
71Each unspecified type is called a _type parameter_.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -070072When running the generic code, the type parameter will be set to a
73_type argument_.
Russ Cox00fd2f62018-08-23 15:11:30 -040074
75Here is a function that prints out each element of a slice, where the
76element type of the slice, here called `T`, is unknown.
77This is a trivial example of the kind of function we want to permit in
78order to support generic programming.
79
80```Go
81// Print prints the elements of a slice.
82// It should be possible to call this with any slice value.
83func Print(s []T) { // Just an example, not the suggested syntax.
84 for _, v := range s {
85 fmt.Println(v)
86 }
87}
88```
89
Ian Lance Taylor4a54a002019-07-26 23:21:48 -070090With this approach, the first decision to make is: how should the type
Russ Cox00fd2f62018-08-23 15:11:30 -040091parameter `T` be declared?
92In a language like Go, we expect every identifier to be declared in
93some way.
94
95Here we make a design decision: type parameters are similar to
96ordinary non-type function parameters, and as such should be listed
97along with other parameters.
98However, type parameters are not the same as non-type parameters, so
Ian Lance Taylor4a54a002019-07-26 23:21:48 -070099although they appear in the list of parameters we want to distinguish
100them.
Russ Cox00fd2f62018-08-23 15:11:30 -0400101That leads to our next design decision: we define an additional,
102optional, parameter list, describing type parameters.
103This parameter list appears before the regular parameters.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700104It starts with the keyword `type`, and lists type parameters.
Russ Cox00fd2f62018-08-23 15:11:30 -0400105
106```Go
107func Print(type T)(s []T) {
108 // same as above
109}
110```
111
112This says that within the function `Print` the identifier `T` is a
113type parameter, a type that is currently unknown but that will be
114known when the function is called.
115
116Since `Print` has a type parameter, when we call it we must pass a
117type argument.
118Type arguments are passed much like type parameters are declared: as a
119separate list of arguments.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700120At the call site, the `type` keyword is not required.
Russ Cox00fd2f62018-08-23 15:11:30 -0400121
122```Go
123 Print(int)([]int{1, 2, 3})
124```
125
126### Type contracts
127
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700128Let's make our example slightly more complicated.
129Let's turn it into a function that converts a slice of any type into a
Russ Cox00fd2f62018-08-23 15:11:30 -0400130`[]string` by calling a `String` method on each element.
131
132```Go
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700133// This function is INVALID.
Russ Cox00fd2f62018-08-23 15:11:30 -0400134func Stringify(type T)(s []T) (ret []string) {
135 for _, v := range s {
136 ret = append(ret, v.String()) // INVALID
137 }
138 return ret
139}
140```
141
142This might seem OK at first glance, but in this example, `v` has type
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700143`T`, and we don't know anything about `T`.
144In particular, we don't know that `T` has a `String` method.
145So the call to `v.String()` is invalid.
Russ Cox00fd2f62018-08-23 15:11:30 -0400146
147Naturally, the same issue arises in other languages that support
148generic programming.
149In C++, for example, a generic function (in C++ terms, a function
150template) can call any method on a value of generic type.
151That is, in the C++ approach, calling `v.String()` is fine.
152If the function is called with a type that does not have a `String`
153method, the error is reported at the point of the function call.
154These errors can be lengthy, as there may be several layers of generic
155function calls before the error occurs, all of which must be reported
156for complete clarity.
157
158The C++ approach would be a poor choice for Go.
159One reason is the style of the language.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700160In Go we don't refer to names, such as, in this case, `String`, and
Russ Cox00fd2f62018-08-23 15:11:30 -0400161hope that they exist.
162Go resolves all names to their declarations when they are seen.
163
164Another reason is that Go is designed to support programming at
165scale.
166We must consider the case in which the generic function definition
167(`Stringify`, above) and the call to the generic function (not shown,
168but perhaps in some other package) are far apart.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700169In general, all generic code implies a contract that type arguments
170need to implement.
Russ Cox00fd2f62018-08-23 15:11:30 -0400171In this case, the contract is pretty obvious: the type has to have a
172`String() string` method.
173In other cases it may be much less obvious.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700174We don't want to derive the contract from whatever `Stringify` happens
Russ Cox00fd2f62018-08-23 15:11:30 -0400175to do.
176If we did, a minor change to `Stringify` might change the contract.
177That would mean that a minor change could cause code far away, that
178calls the function, to unexpectedly break.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700179It's fine for `Stringify` to deliberately change its contract, and
Russ Cox00fd2f62018-08-23 15:11:30 -0400180force users to change.
181What we want to avoid is `Stringify` changing its contract
182accidentally.
183
184This is an important rule that we believe should apply to any attempt
185to define generic programming in Go: there should be an explicit
186contract between the generic code and calling code.
187
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700188### Contract introduction
Russ Cox00fd2f62018-08-23 15:11:30 -0400189
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700190In this design, a contract describes the requirements of a set of
191types.
192We'll discuss contracts further later, but for now we'll just say that
193one of the things that a contract can do is specify that a type
194argument must implement a particular method.
Russ Cox00fd2f62018-08-23 15:11:30 -0400195
196For the `Stringify` example, we need to write a contract that says
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700197that the single type parameter has a `String` method that takes no
198arguments and returns a value of type `string`.
199We write that like this:
Russ Cox00fd2f62018-08-23 15:11:30 -0400200
201```Go
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700202contract stringer(T) {
203 T String() string
Russ Cox00fd2f62018-08-23 15:11:30 -0400204}
205```
206
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700207A contract is introduced with a new keyword `contract`, followed by a
208name and a list of identifiers.
209The identifiers name the types that the contract will specify.
210Specifying a required method looks like defining a method in an
211interface type, except that the receiver type must be explicitly
212provided.
Russ Cox00fd2f62018-08-23 15:11:30 -0400213
214### Using a contract to verify type arguments
215
216A contract serves two purposes.
217First, contracts are used to validate a set of type arguments.
218As shown above, when a function with type parameters is called, it
219will be called with a set of type arguments.
220When the compiler sees the function call, it will use the contract to
221validate the type arguments.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700222If the type arguments don't satisfy the requirements specified by the
223contract, the compiler will report a type error: the call is using
224types that the function's contract does not permit.
Russ Cox00fd2f62018-08-23 15:11:30 -0400225
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700226The `stringer` contract seen earlier requires that the type argument
227used for `T` has a `String` method that takes no arguments and
228returns a value of type `string`.
Russ Cox00fd2f62018-08-23 15:11:30 -0400229
230### The party of the second part
231
232A contract is not used only at the call site.
233It is also used to describe what the function using the contract, the
234function with type parameters, is permitted to do with those type
235parameters.
236
237In a function with type parameters that does not use a contract, such
238as the `Print` example shown earlier, the function is only permitted
239to use those type parameters in ways that any type may be used in Go.
240That is, operations like:
241
242* declare variables of those types
243* assign other values of the same type to those variables
244* pass those variables to functions or return them from functions
245* take the address of those variables
246* define and use other types that use those types, such as a slice of
247 that type
248
249If the function wants to take any more specific action with the type
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700250parameter, or a value of the type parameter, the contract must
251explicitly support that action.
252In the `stringer` example seen earlier, the contract provides the
253ability to call a method `String` on a value of the type parameter.
Russ Cox00fd2f62018-08-23 15:11:30 -0400254That is, naturally, exactly the operation that the `Stringify`
255function needs.
256
257### Using a contract
258
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700259We've seen how the `stringer` contract can be used to verify that a
260type argument is suitable for the `Stringify` function, and we've seen
Russ Cox00fd2f62018-08-23 15:11:30 -0400261how the contract permits the `Stringify` function to call the `String`
262method that it needs.
263The final step is showing how the `Stringify` function uses the
264`stringer` contract.
265This is done by naming the contract at the end of the list of type
266parameters.
267
268```Go
269func Stringify(type T stringer)(s []T) (ret []string) {
270 for _, v := range s {
271 ret = append(ret, v.String()) // now valid
272 }
273 return ret
274}
275```
276
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700277The list of type parameters (in this case, a list with the single
278element `T`) is followed by an optional contract name.
279When just the contract name is listed, as above, the contract must
280have the same number of parameters as the function has type
281parameters; when validating the contract, the type parameters are
282passed to the contract in the order in which they appear in the
283function signature.
284Later we'll discuss passing explicit type parameters to the contract.
Russ Cox00fd2f62018-08-23 15:11:30 -0400285
286### Multiple type parameters
287
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700288Although the examples we've seen so far use only a single type
289parameter, functions may have multiple type parameters.
Russ Cox00fd2f62018-08-23 15:11:30 -0400290
291```Go
292func Print2(type T1, T2)(s1 []T1, s2 []T2) { ... }
293```
294
295Compare this to
296
297```Go
298func Print2Same(type T1)(s1 []T1, s2 []T1) { ... }
299```
300
301In `Print2` `s1` and `s2` may be slices of different types.
302In `Print2Same` `s1` and `s2` must be slices of the same element
303type.
304
305Although functions may have multiple type parameters, they may only
306have a single contract.
307
308```Go
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700309contract viaStrings(To, From) {
310 To Set(string)
311 From String() string
Russ Cox00fd2f62018-08-23 15:11:30 -0400312}
313
314func SetViaStrings(type To, From viaStrings)(s []From) []To {
315 r := make([]To, len(s))
316 for i, v := range s {
317 r[i].Set(v.String())
318 }
319 return r
320}
321```
322
323### Parameterized types
324
325We want more than just generic functions: we also want generic types.
326We suggest that types be extended to take type parameters.
327
328```Go
329type Vector(type Element) []Element
330```
331
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700332A type's parameters are just like a function's type parameters.
Russ Cox00fd2f62018-08-23 15:11:30 -0400333
334Within the type definition, the type parameters may be used like any
335other type.
336
337To use a parameterized type, you must supply type arguments.
338This looks like a function call, except that the function in this case
339is actually a type.
340This is called _instantiation_.
341
342```Go
343var v Vector(int)
344```
345
346Parameterized types can have methods.
347The receiver type of a method must list the type parameters.
348They are listed without the `type` keyword or any contract.
349
350```Go
351func (v *Vector(Element)) Push(x Element) { *v = append(*v, x) }
352```
353
354A parameterized type can refer to itself in cases where a type can
355ordinarily refer to itself, but when it does so the type arguments
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700356must be the type parameters, listed in the same order.
357This restriction prevents infinite recursion of type instantiation.
Russ Cox00fd2f62018-08-23 15:11:30 -0400358
359```Go
360// This is OK.
361type List(type Element) struct {
362 next *List(Element)
363 val Element
364}
365
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700366// This type is INVALID.
Russ Cox00fd2f62018-08-23 15:11:30 -0400367type P(type Element1, Element2) struct {
368 F *P(Element2, Element1) // INVALID; must be (Element1, Element2)
369}
370```
371
372(Note: with more understanding of how people want to write code, it
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700373may be possible to relax this rule to permit some cases that use
374different type arguments.)
375
376The type parameter of a parameterized type may have contracts.
377
378```Go
379type StringableVector(type T stringer) []T
380
381func (s StringableVector(T)) String() string {
382 var sb strings.Builder
383 sb.WriteString("[")
384 for i, v := range s {
385 if i > 0 {
386 sb.WriteString(", ")
387 }
388 sb.WriteString(v.String())
389 }
390 sb.WriteString("]")
391 return sb.String()
392}
393```
Russ Cox00fd2f62018-08-23 15:11:30 -0400394
395When a parameterized type is a struct, and the type parameter is
396embedded as a field in the struct, the name of the field is the name
397of the type parameter, not the name of the type argument.
398
399```Go
400type Lockable(type T) struct {
401 T
402 mu sync.Mutex
403}
404
405func (l *Lockable(T)) Get() T {
406 l.mu.Lock()
407 defer l.mu.Unlock()
408 return l.T
409}
410```
411
Russ Cox00fd2f62018-08-23 15:11:30 -0400412### Parameterized type aliases
413
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700414Type aliases may not have parameters.
415This restriction exists because it is unclear how to handle a type
416alias with type parameters that have a contract.
Russ Cox00fd2f62018-08-23 15:11:30 -0400417
418Type aliases may refer to instantiated types.
419
420```Go
421type VectorInt = Vector(int)
422```
423
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700424If a type alias refers to a parameterized type, it must provide type
425arguments.
426
Russ Cox00fd2f62018-08-23 15:11:30 -0400427### Methods may not take additional type arguments
428
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700429Although methods of a parameterized type may use the type's
430parameters, methods may not themselves have additional type
Russ Cox00fd2f62018-08-23 15:11:30 -0400431parameters.
432Where it would be useful to add type arguments to a method, people
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700433will have to write a suitably parameterized top-level function.
Russ Cox00fd2f62018-08-23 15:11:30 -0400434
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700435This restriction avoids having to specify the details of exactly when
436a method with type arguments implements an interface.
Russ Cox00fd2f62018-08-23 15:11:30 -0400437(This is a feature that can perhaps be added later if it proves
438necessary.)
439
440### Contract embedding
441
442A contract may embed another contract, by listing it in the
443contract body with type arguments.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700444This will look a bit like a method definition in the contract body,
445but it will be different because there will be no receiver type.
446It is handled as if the embedded contract's body were placed into the
447calling contract, with the embedded contract's type parameters
448replaced by the embedded type arguments.
Russ Cox00fd2f62018-08-23 15:11:30 -0400449
450This contract embeds the contract `stringer` defined earlier.
451
452```Go
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700453contract PrintStringer(X) {
Russ Cox00fd2f62018-08-23 15:11:30 -0400454 stringer(X)
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700455 X Print()
Russ Cox00fd2f62018-08-23 15:11:30 -0400456}
457```
458
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700459This is equivalent to
Russ Cox00fd2f62018-08-23 15:11:30 -0400460
461```Go
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700462contract PrintStringer(X) {
Ian Lance Taylorca869dd2019-07-31 10:30:47 -0700463 X String() string
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700464 X Print()
Russ Cox00fd2f62018-08-23 15:11:30 -0400465}
466```
467
Russ Cox00fd2f62018-08-23 15:11:30 -0400468### Using types that refer to themselves in contracts
469
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700470Although this is implied by what has already been discussed, it's
Russ Cox00fd2f62018-08-23 15:11:30 -0400471worth pointing out explicitly that a contract may require a method to
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700472have an argument whose type is the same as the method's receiver
473type.
Russ Cox00fd2f62018-08-23 15:11:30 -0400474
475```Go
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700476package compare
Russ Cox00fd2f62018-08-23 15:11:30 -0400477
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700478// The equal contract describes types that have an Equal method with
479// an argument of the same type as the receiver type.
480contract equal(T) {
481 T Equal(T) bool
Russ Cox00fd2f62018-08-23 15:11:30 -0400482}
483
484// Index returns the index of e in s, or -1.
485func Index(type T equal)(s []T, e T) int {
486 for i, v := range s {
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700487 // Both e and v are type T, so it's OK to call e.Equal(v).
Russ Cox00fd2f62018-08-23 15:11:30 -0400488 if e.Equal(v) {
489 return i
490 }
491 }
492 return -1
493}
494```
495
496This function can be used with any type that has an `Equal` method
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700497whose single parameter type is the same as the receiver type.
Russ Cox00fd2f62018-08-23 15:11:30 -0400498
499```Go
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700500import "compare"
Russ Cox00fd2f62018-08-23 15:11:30 -0400501
502type EqualInt int
503
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700504// The Equal method lets EqualInt satisfy the compare.equal contract.
Russ Cox00fd2f62018-08-23 15:11:30 -0400505func (a EqualInt) Equal(b EqualInt) bool { return a == b }
506
507func Index(s []EqualInt, e EqualInt) int {
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700508 return compare.Index(EqualInt)(s, e)
Russ Cox00fd2f62018-08-23 15:11:30 -0400509}
510```
511
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700512In this example, when we pass `EqualInt` to `compare.Index`, we
513check whether `EqualInt` satisfies the contract `compare.equal`.
514We replace `T` with `EqualInt` in the declaration of the `Equal`
515method in the `equal` contract, and see whether `EqualInt` has a
516matching method.
Russ Cox00fd2f62018-08-23 15:11:30 -0400517`EqualInt` has a method `Equal` that accepts a parameter of type
518`EqualInt`, so all is well, and the compilation succeeds.
519
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700520### Mutually referencing type parameters
Russ Cox00fd2f62018-08-23 15:11:30 -0400521
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700522Within a contract, methods may refer to any of the contract's type
523parameters.
Russ Cox00fd2f62018-08-23 15:11:30 -0400524
525For example, consider a generic graph package that contains generic
526algorithms that work with graphs.
527The algorithms use two types, `Node` and `Edge`.
528`Node` is expected to have a method `Edges() []Edge`.
529`Edge` is expected to have a method `Nodes() (Node, Node)`.
530A graph can be represented as a `[]Node`.
531
532This simple representation is enough to implement graph algorithms
533like finding the shortest path.
534
535```Go
536package graph
537
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700538contract G(Node, Edge) {
539 Node Edges() []Edge
540 Edge Nodes() (from Node, to Node)
Russ Cox00fd2f62018-08-23 15:11:30 -0400541}
542
543type Graph(type Node, Edge G) struct { ... }
544func New(type Node, Edge G)(nodes []Node) *Graph(Node, Edge) { ... }
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700545func (g *Graph(Node, Edge)) ShortestPath(from, to Node) []Edge { ... }
Russ Cox00fd2f62018-08-23 15:11:30 -0400546```
547
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700548While at first glance this may look like a typical use of interface
549types, `Node` and `Edge` are non-interface types with specific
550methods.
Russ Cox00fd2f62018-08-23 15:11:30 -0400551In order to use `graph.Graph`, the type arguments used for `Node` and
552`Edge` have to define methods that follow a certain pattern, but they
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700553don't have to actually use interface types to do so.
Russ Cox00fd2f62018-08-23 15:11:30 -0400554
555For example, consider these type definitions in some other package:
556
557```Go
558type Vertex struct { ... }
559func (v *Vertex) Edges() []*FromTo { ... }
560type FromTo struct { ... }
Christian Himpelbf0f39f2019-07-30 11:14:26 +0200561func (ft *FromTo) Nodes() (*Vertex, *Vertex) { ... }
Russ Cox00fd2f62018-08-23 15:11:30 -0400562```
563
564There are no interface types here, but we can instantiate
565`graph.Graph` using the type arguments `*Vertex` and `*FromTo`:
566
567```Go
568var g = graph.New(*Vertex, *FromTo)([]*Vertex{ ... })
569```
570
571`*Vertex` and `*FromTo` are not interface types, but when used
572together they define methods that implement the contract `graph.G`.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700573Note that we couldn't use plain `Vertex` or `FromTo`, since the
574required methods are pointer methods, not value methods.
Russ Cox00fd2f62018-08-23 15:11:30 -0400575
576Although `Node` and `Edge` do not have to be instantiated with
577interface types, it is also OK to use interface types if you like.
578
579```Go
580type NodeInterface interface { Edges() []EdgeInterface }
581type EdgeInterface interface { Nodes() (NodeInterface, NodeInterface) }
582```
583
584We could instantiate `graph.Graph` with the types `NodeInterface` and
585`EdgeInterface`, since they implement the `graph.G` contract.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700586There isn't much reason to instantiate a type this way, but it is
Russ Cox00fd2f62018-08-23 15:11:30 -0400587permitted.
588
589This ability for type parameters to refer to other type parameters
590illustrates an important point: it should be a requirement for any
591attempt to add generics to Go that it be possible to instantiate
592generic code with multiple type arguments that refer to each other in
593ways that the compiler can check.
594
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700595As it is a common observation that contracts share some
596characteristics of interface types, it's worth stressing that this
597capability is one that contracts provide but interface types do not.
598
599### Passing parameters to a contract
600
601As mentioned earlier, by default the type parameters are passed to the
602contract in the order in which they appear in the function signature.
603It is also possible to explicitly pass type parameters to a contract
604as though they were arguments.
605This is useful if the contract and the generic function take type
606parameters in a different order, or if only some parameters need a
607contract.
608
609In this example the type parameter `E` can be any type, but the type
610parameter `M` must implement the `String` method.
611The function passes just `M` to the `stringer` contract, leaving `E`
612as though it had no constraints.
613
614```Go
615func MapAndPrint(type E, M stringer(M))(s []E, f(E) M) []string {
616 r := make([]string, len(s))
617 for i, v := range s {
618 r[i] = f(v).String()
619 }
620 return r
621}
622```
623
624### Contract syntactic details
625
626Contracts may only appear at the top level of a package.
627
628While contracts could be defined to work within the body of a
629function, it's hard to think of realistic examples in which they would
630be useful.
631We see this as similar to the way that methods can not be defined
632within the body of a function.
633A minor point is that only permitting contracts at the top level
634permits the design to be Go 1 compatible.
635
636There are a few ways to handle the syntax:
637
638* We could make `contract` be a keyword only at the start of a
639 top-level declaration, and otherwise be a normal identifier.
640* We could declare that if you use `contract` at the start of a
641 top-level declaration, then it becomes a keyword for the entire
642 package.
643* We could make `contract` always be a keyword, albeit one that can
644 only appear in one place, in which case this design is not Go 1
645 compatible.
646
647Like other top level declarations, a contract is exported if its name
648starts with an uppercase letter.
649If exported it may be used by functions, types, or contracts in other
650packages.
651
Russ Cox00fd2f62018-08-23 15:11:30 -0400652### Values of type parameters are not boxed
653
654In the current implementations of Go, interface values always hold
655pointers.
656Putting a non-pointer value in an interface variable causes the value
657to be _boxed_.
658That means that the actual value is stored somewhere else, on the heap
659or stack, and the interface value holds a pointer to that location.
660
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700661In this design, values of generic types are not boxed.
662For example, let's consider a function that works for any type `T`
Russ Cox00fd2f62018-08-23 15:11:30 -0400663with a `Set(string)` method that initializes the value based on a
664string, and uses it to convert a slice of `string` to a slice of `T`.
665
666```Go
667package from
668
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700669contract setter(T) {
670 T Set(string) error
Russ Cox00fd2f62018-08-23 15:11:30 -0400671}
672
673func Strings(type T setter)(s []string) ([]T, error) {
674 ret := make([]T, len(s))
675 for i, v := range s {
676 if err := ret[i].Set(v); err != nil {
677 return nil, err
678 }
679 }
680 return ret, nil
681}
682```
683
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700684Now let's see some code in a different package.
Russ Cox00fd2f62018-08-23 15:11:30 -0400685
686```Go
687type Settable int
688
689func (p *Settable) Set(s string) (err error) {
690 *p, err = strconv.Atoi(s)
691 return err
692}
693
694func F() {
695 // The type of nums is []Settable.
696 nums, err := from.Strings(Settable)([]string{"1", "2"})
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700697 if err != nil { ... }
Russ Cox00fd2f62018-08-23 15:11:30 -0400698 // Settable can be converted directly to int.
699 // This will set first to 1.
700 first := int(nums[0])
701 ...
702}
703```
704
705When we call `from.Strings` with the type `Settable` we get back a
706`[]Settable` (and an error).
707The values in that slice will be `Settable` values, which is to say,
708they will be integers.
709They will not be boxed as pointers, even though they were created and
710set by a generic function.
711
712Similarly, when a parameterized type is instantiated it will have the
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700713expected types as components.
Russ Cox00fd2f62018-08-23 15:11:30 -0400714
715```Go
716package pair
717
718type Pair(type carT, cdrT) struct {
719 f1 carT
720 f2 cdrT
721}
722```
723
724When this is instantiated, the fields will not be boxed, and no
725unexpected memory allocations will occur.
726The type `pair.Pair(int, string)` is convertible to `struct { f1 int;
727f2 string }`.
728
729### Function argument type inference
730
731In many cases, when calling a function with type parameters, we can
732use type inference to avoid having to explicitly write out the type
733arguments.
734
735Go back to the example of a call to our simple `Print` function:
736
737```Go
738 Print(int)([]int{1, 2, 3})
739```
740
741The type argument `int` in the function call can be inferred from the
742type of the non-type argument.
743
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700744This can only be done when all the function's type parameters are used
745for the types of the function's (non-type) input parameters.
Russ Cox00fd2f62018-08-23 15:11:30 -0400746If there are some type parameters that are used only for the
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700747function's result parameter types, or only in the body of the
Russ Cox00fd2f62018-08-23 15:11:30 -0400748function, then it is not possible to infer the type arguments for the
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700749function, since there is no value from which to infer the types.
Russ Cox00fd2f62018-08-23 15:11:30 -0400750For example, when calling `from.Strings` as defined earlier, the type
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700751parameters cannot be inferred because the function's type parameter
Russ Cox00fd2f62018-08-23 15:11:30 -0400752`T` is not used for an input parameter, only for a result.
753
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700754When the function's type arguments can be inferred, the language uses
Russ Cox00fd2f62018-08-23 15:11:30 -0400755type unification.
756On the caller side we have the list of types of the actual (non-type)
757arguments, which for the `Print` example here is simply `[]int`.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700758On the function side is the list of the types of the function's
Russ Cox00fd2f62018-08-23 15:11:30 -0400759non-type parameters, which here is `[]T`.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700760In the lists, we discard respective arguments for which the function
761side does not use a type parameter.
Russ Cox00fd2f62018-08-23 15:11:30 -0400762We must then unify the remaining argument types.
763
764Type unification is a two pass algorithm.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700765In the first pass, we ignore untyped constants on the caller side and
766their corresponding types in the function definition.
Russ Cox00fd2f62018-08-23 15:11:30 -0400767
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700768We compare corresponding types in the lists.
Russ Cox00fd2f62018-08-23 15:11:30 -0400769Their structure must be identical, except that type parameters on the
770function side match the type that appears on the caller side at the
771point where the type parameter occurs.
772If the same type parameter appears more than once on the function
773side, it will match multiple argument types on the caller side.
774Those caller types must be identical, or type unification fails, and
775we report an error.
776
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700777After the first pass, we check any untyped constants on the caller
778side.
Russ Cox00fd2f62018-08-23 15:11:30 -0400779If there are no untyped constants, or if the type parameters in the
780corresponding function types have matched other input types, then
781type unification is complete.
782
783Otherwise, for the second pass, for any untyped constants whose
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700784corresponding function types are not yet set, we determine the default
Russ Cox00fd2f62018-08-23 15:11:30 -0400785type of the untyped constant in [the usual
786way](https://golang.org/ref/spec#Constants).
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700787Then we run the type unification algorithm again, this time with no
Russ Cox00fd2f62018-08-23 15:11:30 -0400788untyped constants.
789
790In this example
791
792```Go
793 s1 := []int{1, 2, 3}
794 Print(s1)
795```
796
797we compare `[]int` with `[]T`, match `T` with `int`, and we are done.
798The single type parameter `T` is `int`, so we infer that the call
799to `Print` is really a call to `Print(int)`.
800
801For a more complex example, consider
802
803```Go
804package transform
805
806func Slice(type From, To)(s []From, f func(From) To) []To {
807 r := make([]To, len(s))
808 for i, v := range s {
809 r[i] = f(v)
810 }
811 return r
812}
813```
814
815The two type parameters `From` and `To` are both used for input
816parameters, so type inference is possible.
817In the call
818
819```Go
820 strs := transform.Slice([]int{1, 2, 3}, strconv.Itoa)
821```
822
823we unify `[]int` with `[]From`, matching `From` with `int`.
824We unify the type of `strconv.Itoa`, which is `func(int) string`,
825with `func(From) To`, matching `From` with `int` and `To` with
826`string`.
827`From` is matched twice, both times with `int`.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700828Unification succeeds, so the call written as `transform.Slice` is a
829call of `transform.Slice(int, string)`.
Russ Cox00fd2f62018-08-23 15:11:30 -0400830
831To see the untyped constant rule in effect, consider
832
833```Go
834package pair
835
836func New(type T)(f1, f2 T) *Pair(T) { ... }
837```
838
839In the call `pair.New(1, 2)` both arguments are untyped constants, so
840both are ignored in the first pass.
841There is nothing to unify.
842We still have two untyped constants after the first pass.
843Both are set to their default type, `int`.
844The second run of the type unification pass unifies `T` with `int`,
845so the final call is `pair.New(int)(1, 2)`.
846
847In the call `pair.New(1, int64(2))` the first argument is an untyped
848constant, so we ignore it in the first pass.
849We then unify `int64` with `T`.
850At this point the type parameter corresponding to the untyped constant
851is fully determined, so the final call is `pair.New(int64)(1, int64(2))`.
852
853In the call `pair.New(1, 2.5)` both arguments are untyped constants,
854so we move on the second pass.
855This time we set the first constant to `int` and the second to
856`float64`.
857We then try to unify `T` with both `int` and `float64`, so
858unification fails, and we report a compilation error.
859
860Note that type inference is done without regard to contracts.
861First we use type inference to determine the type arguments to use for
862the package, and then, if that succeeds, we check whether those type
863arguments implement the contract.
864
865Note that after successful type inference, the compiler must still
866check that the arguments can be assigned to the parameters, as for any
867function call.
868This need not be the case when untyped constants are involved.
869
870(Note: Type inference is a convenience feature.
871Although we think it is an important feature, it does not add any
872functionality to the design, only convenience in using it.
873It would be possible to omit it from the initial implementation, and
874see whether it seems to be needed.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700875That said, this feature doesn't require additional syntax, and is
Russ Cox00fd2f62018-08-23 15:11:30 -0400876likely to significantly reduce the stutter of repeated type arguments
877in code.)
878
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700879(Note: We could also consider supporting type inference for
880composite literals of parameterized types.
Russ Cox00fd2f62018-08-23 15:11:30 -0400881
882```Go
883type Pair(type T) struct { f1, f2 T }
884var V = Pair{1, 2} // inferred as Pair(int){1, 2}
885```
886
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700887It's not clear how often this will arise in real code.)
Russ Cox00fd2f62018-08-23 15:11:30 -0400888
889### Instantiating a function
890
891Go normally permits you to refer to a function without passing any
892arguments, producing a value of function type.
893You may not do this with a function that has type parameters; all type
894arguments must be known at compile time.
895However, you can instantiate the function, by passing type arguments,
896without passing any non-type arguments.
897This will produce an ordinary function value with no type parameters.
898
899```Go
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700900// PrintInts will be type func([]int).
Russ Cox00fd2f62018-08-23 15:11:30 -0400901var PrintInts = Print(int)
902```
903
904### Type assertions and switches
905
906A useful function with type parameters will support any type argument
907that implements the contract.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700908Sometimes, though, it's possible to use a more efficient
909function implementation for some type arguments.
Russ Cox00fd2f62018-08-23 15:11:30 -0400910The language already has mechanisms for code to find out what type it
911is working with: type assertions and type switches.
912Those are normally only permitted with interface types.
913In this design, functions are also permitted to use them with values
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700914whose types are type parameters, or are based on type parameters.
Russ Cox00fd2f62018-08-23 15:11:30 -0400915
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700916This doesn't add any functionality, as the function could get the same
Russ Cox00fd2f62018-08-23 15:11:30 -0400917information using the reflect package.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700918It's merely occasionally convenient, and it may result in more
Russ Cox00fd2f62018-08-23 15:11:30 -0400919efficient code.
920
921For example, this code is permitted even if it is called with a type
922argument that is not an interface type.
923
924```Go
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700925contract reader(T) {
926 T Read([]byte) (int, error)
Russ Cox00fd2f62018-08-23 15:11:30 -0400927}
928
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700929func ReadByte(type T reader)(r T) (byte, error) {
Russ Cox00fd2f62018-08-23 15:11:30 -0400930 if br, ok := r.(io.ByteReader); ok {
931 return br.ReadByte()
932 }
933 var b [1]byte
934 _, err := r.Read(b[:])
935 return b[0], err
936}
937```
938
939### Instantiating types in type literals
940
941When instantiating a type at the end of a type literal, there is a
942parsing ambiguity.
943
944```Go
945x1 := []T(v1)
946x2 := []T(v2){}
947```
948
949In this example, the first case is a type conversion of `v1` to the
950type `[]T`.
951The second case is a composite literal of type `[]T(v2)`, where `T` is
952a parameterized type that we are instantiating with the type argument
953`v2`.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700954The ambiguity is at the point where we see the open parenthesis: at
955that point the parser doesn't know whether it is seeing a type
956conversion or something like a composite literal.
Russ Cox00fd2f62018-08-23 15:11:30 -0400957
958To avoid this ambiguity, we require that type instantiations at the
959end of a type literal be parenthesized.
Russ Cox00fd2f62018-08-23 15:11:30 -0400960To write a type literal that is a slice of a type instantiation, you
961must write `[](T(v1))`.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700962Without those parentheses, `[]T(x)` is parsed as `([]T)(x)`, not as
963`[](T(x))`.
Russ Cox00fd2f62018-08-23 15:11:30 -0400964This only applies to slice, array, map, chan, and func type literals
965ending in a type name.
966Of course it is always possible to use a separate type declaration to
967give a name to the instantiated type, and to use that.
968This is only an issue when the type is instantiated in place.
969
Ian Lance Taylor4a54a002019-07-26 23:21:48 -0700970### Using parameterized types as unnamed function parameter types
971
972When parsing a parameterized type as an unnamed function parameter
973type, there is a parsing ambiguity.
974
975```Go
976var f func(x(T))
977```
978
979In this example we don't know whether the function has a single
980unnamed parameter of the parameterized type `x(T)`, or whether this is
981a named parameter `x` of the type `(T)` (written with parentheses).
982
983For backward compatibility, we treat this as the latter case: `x(T)`
984is a parameter `x` of type `(T)`.
985In order to describe a function with a single unnamed parameter of
986type `x(T)`, either the parameter must be named, or extra parentheses
987must be used.
988
989```Go
990var f1 func(_ x(T))
991var f2 func((x(T)))
992```
993
Robert Griesemer020fa4d2020-02-26 13:17:55 -0800994### Embedding a parameterized type in a struct
995
996There is a parsing ambiguity when embedding a parameterized type
997in a struct type.
998
999```Go
1000type S1(type T) struct {
1001 f T
1002}
1003
1004type S2 struct {
1005 S1(int)
1006}
1007```
1008
1009In this example we don't know whether struct `S2` has a single
1010field named `S1` of type `(int)`, or whether we
1011are trying to embed the instantiated type `S1(int)` into `S2`.
1012
1013For backward compatibility, we treat this as the former case: `S2` has
1014a field named `S1`.
1015
1016In order to embed an instantiated type in a struct, we could require that
1017extra parentheses be used.
1018
1019```Go
1020type S2 struct {
1021 (S1(int))
1022}
1023```
1024
1025This is currently not supported by the language, so this would suggest
1026generally extending the language to permit types embedded in structs to
1027be parenthesized.
1028
1029### Embedding a parameterized interface type in an interface
Ian Lance Taylorca869dd2019-07-31 10:30:47 -07001030
1031There is a parsing ambiguity when embedding a parameterized interface
1032type in another interface type.
1033
1034```Go
1035type I1(type T) interface {
1036 M(T)
1037}
1038
1039type I2 interface {
1040 I1(int)
1041}
1042```
1043
1044In this example we don't know whether interface `I2` has a single
1045method named `I1` that takes an argument of type `int`, or whether we
1046are trying to embed the instantiated type `I1(int)` into `I2`.
1047
1048For backward compatibility, we treat this as the former case: `I2` has
1049a method named `I1`.
1050
1051In order to embed an instantiated interface, we could require that
1052extra parentheses be used.
1053
1054```Go
1055type I2 interface {
1056 (I1(int))
1057}
1058```
1059
1060This is currently not supported by the language, so this would suggest
1061generally extending the language to permit embedded interface types to
1062be parenthesized.
1063
Russ Cox00fd2f62018-08-23 15:11:30 -04001064### Reflection
1065
1066We do not propose to change the reflect package in any way.
1067When a type or function is instantiated, all of the type parameters
1068will become ordinary non-generic types.
1069The `String` method of a `reflect.Type` value of an instantiated type
1070will return the name with the type arguments in parentheses.
1071For example, `List(int)`.
1072
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001073It's impossible for non-generic code to refer to generic code without
Russ Cox00fd2f62018-08-23 15:11:30 -04001074instantiating it, so there is no reflection information for
1075uninstantiated generic types or functions.
1076
1077### Contracts details
1078
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001079Let's take a deeper look at contracts.
Russ Cox00fd2f62018-08-23 15:11:30 -04001080
1081Operations on values whose type is a type parameter must be permitted
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001082by the type parameter's contract.
Russ Cox00fd2f62018-08-23 15:11:30 -04001083This means that the power of generic functions is tied precisely to
1084the interpretation of the contract body.
1085It also means that the language requires a precise definition of the
1086operations that are permitted by a given contract.
1087
Russ Cox00fd2f62018-08-23 15:11:30 -04001088#### Methods
1089
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001090All the contracts we've seen so far show only method calls in the
1091contract body.
Russ Cox00fd2f62018-08-23 15:11:30 -04001092If a method call appears in the contract body, that method may be
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001093called on a value in any statement or expression in the function
1094body.
1095It will take argument and result types as specified in the contract
1096body.
Russ Cox00fd2f62018-08-23 15:11:30 -04001097
Ian Lance Taylorca869dd2019-07-31 10:30:47 -07001098#### Pointer methods
1099
1100In some cases we need to require that a method be a pointer method.
1101This will happen when a function needs to declare variables whose
1102type is the type parameter, and also needs to call methods that are
1103defined for the pointer to the type parameter.
1104
1105For example:
1106
1107```Go
1108contract setter(T) {
1109 T Set(string)
1110}
1111
1112func Init(type T setter)(s string) T {
1113 var r T
1114 r.Set(s)
1115 return r
1116}
1117
1118type MyInt int
1119
1120func (p *MyInt) Set(s string) {
1121 v, err := strconv.Atoi(s)
1122 if err != nil {
1123 log.Fatal("Init failed", err)
1124 }
1125 *p = MyInt(v)
1126}
1127
1128// INVALID
1129// MyInt does not have a Set method, only *MyInt has one.
1130var Init1 = Init(MyInt)("1")
1131
1132// DOES NOT WORK
1133// r in Init is type *MyInt with value nil,
1134// so the Set method does a nil pointer deference.
1135var Init2 = Init(*MyInt)("2")
1136```
1137
1138The function `Init` cannot be instantiated with the type `MyInt`, as
1139that type does not have a method `Set`; only `*MyInt` has `Set`.
1140
1141But instantiating `Init` with `*MyInt` doesn't work either, as then
1142the local variable `r` in `Init` is a value of type `*MyInt`
1143initialized to the zero value, which for a pointer is `nil`.
1144The `Init` function then invokes the `Set` method on a `nil` pointer,
1145causing a `nil` pointer dereference at the line `*p = MyInt(v)`.
1146
1147In order to permit this kind of code, contracts permit specifying that
1148for a type parameter `T` the pointer type `*T` has a method.
1149
1150```Go
1151contract setter(T) {
1152 *T Set(string)
1153}
1154```
1155
1156With this definition of `setter`, instantiating `Init` with `MyInt` is
1157valid and the code works.
1158The local variable `r` has type `MyInt`, and the address of `r` is
1159passed as the receiver of the `Set` pointer method.
1160Instantiating `Init` with `*MyInt` is now invalid, as the type
1161`**MyInt` does not have a method `Set`.
1162
1163Listing a `*T` method in a contract means that the method must be on
1164the type `*T`, and it means that the parameterized function is only
1165permitted to call the method on an addressable value of type `T`.
1166
1167#### Pointer or value methods
1168
1169If a method is listed in a contract with a plain `T` rather than `*T`,
1170then it may be either a pointer method or a value method of `T`.
1171In order to avoid worrying about this distinction, in a generic
1172function body all method calls will be pointer method calls.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001173If necessary, the function body will insert temporary variables,
1174not seen by the user, in order to get an addressable variable to use
1175to call the method.
Russ Cox00fd2f62018-08-23 15:11:30 -04001176
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001177For example, this code is valid, even though `LookupAsString` calls
1178`String` in a context that requires a value method, and `MyInt` only
1179has a pointer method.
Russ Cox00fd2f62018-08-23 15:11:30 -04001180
1181```Go
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001182func LookupAsString(type T stringer)(m map[int]T, k int) string {
1183 return m[k].String() // Note: calls method on value of type T
Russ Cox00fd2f62018-08-23 15:11:30 -04001184}
1185
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001186type MyInt int
1187func (p *MyInt) String() { return strconv.Itoa(int(*p)) }
1188func F(m map[int]MyInt) string {
1189 return LookupAsString(MyInt)(m, 0)
Russ Cox00fd2f62018-08-23 15:11:30 -04001190}
1191```
1192
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001193This makes it easier to understand which types satisfy a contract, and
1194how a contract may be used.
1195It has the drawback that in some cases a pointer method that modifies
1196the value to which the receiver points may be called on a temporary
1197variable that is discarded after the method completes.
1198It may be possible to add a vet warning for a case where a generic
1199function uses a temporary variable for a method call and the function
1200is instantiated with a type that has only a pointer method, not a
1201value method.
Russ Cox00fd2f62018-08-23 15:11:30 -04001202
Ian Lance Taylorca869dd2019-07-31 10:30:47 -07001203(Note: we should revisit this decision if it leads to confusion or
1204incorrect code.)
1205
Russ Cox00fd2f62018-08-23 15:11:30 -04001206#### Operators
1207
1208Method calls are not sufficient for everything we want to express.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001209Consider this simple function that returns the smallest element of a
1210slice of values, where the slice is assumed to be non-empty.
Russ Cox00fd2f62018-08-23 15:11:30 -04001211
1212```Go
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001213// This function is INVALID.
1214func Smallest(type T)(s []T) T {
1215 r := s[0] // panics if slice is empty
1216 for _, v := range s[1:] {
1217 if v < r { // INVALID
1218 r = v
Russ Cox00fd2f62018-08-23 15:11:30 -04001219 }
1220 }
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001221 return r
Russ Cox00fd2f62018-08-23 15:11:30 -04001222}
1223```
1224
1225Any reasonable generics implementation should let you write this
1226function.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001227The problem is the expression `v < r`.
1228This assumes that `T` supports the `<` operator, but there is no
Russ Cox00fd2f62018-08-23 15:11:30 -04001229contract requiring that.
1230Without a contract the function body can only use operations that are
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001231available for all types, but not all Go types support `<`.
Russ Cox00fd2f62018-08-23 15:11:30 -04001232
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001233It follows that we need a way to write a contract that accepts only
1234types that support `<`.
1235In order to do that, we observe that, aside from two exceptions that
1236we will discuss later, all the arithmetic, comparison, and logical
1237operators defined by the language may only be used with types that are
1238predeclared by the language, or with defined types whose underlying
1239type is one of those predeclared types.
1240That is, the operator `<` can only be used with a predeclared type
1241such as `int` or `float64`, or a defined type whose underlying type is
1242one of those types.
1243Go does not permit using `<` with an aggregate type or with an
1244arbitrary defined type.
1245
1246This means that rather than try to write a contract for `<`, we can
1247approach this the other way around: instead of saying which operators
1248a contract should support, we can say which (underlying) types a
1249contract should accept.
1250
1251#### Types in contracts
1252
1253A contract may list explicit types that may be used as type
1254arguments.
1255These are expressed in the form `type-parameter-name type, type...`.
1256The `type` must be a predeclared type, such as `int`, or an aggregate
1257as discussed below.
1258For example,
Russ Cox00fd2f62018-08-23 15:11:30 -04001259
1260```Go
Ian Lance Taylorca869dd2019-07-31 10:30:47 -07001261contract SignedInteger(T) {
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001262 T int, int8, int16, int32, int64
Russ Cox00fd2f62018-08-23 15:11:30 -04001263}
1264```
1265
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001266This contract specifies that the type argument must be one of the
1267listed types (`int`, `int8`, and so forth), or it must be a defined
1268type whose underlying type is one of the listed types.
Russ Cox00fd2f62018-08-23 15:11:30 -04001269
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001270When a parameterized function using this contract has a value of type
1271`T`, it may use any operation that is permitted by all of the listed
1272types.
1273This can be an operation like `<`, or for aggregate types an operation
1274like `range` or `<-`.
1275If the function can be compiled successfully using each type listed in
1276the contract, then the operation is permitted.
Russ Cox00fd2f62018-08-23 15:11:30 -04001277
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001278For the `Smallest` example shown earlier, we could use a contract like
1279this:
Russ Cox00fd2f62018-08-23 15:11:30 -04001280
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001281```Go
1282contract Ordered(T) {
1283 T int, int8, int16, int32, int64,
Ian Lance Taylorca869dd2019-07-31 10:30:47 -07001284 uint, uint8, uint16, uint32, uint64, uintptr,
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001285 float32, float64,
1286 string
1287}
1288```
Russ Cox00fd2f62018-08-23 15:11:30 -04001289
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001290(In practice this contract would likely be defined and exported in a
1291new standard library package, `contracts`, so that it could be used by
1292function and type and contract definitions.)
Russ Cox00fd2f62018-08-23 15:11:30 -04001293
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001294Given that contract, we can write this function, now valid:
1295
1296```Go
1297func Smallest(type T Ordered)(s []T) T {
1298 r := s[0] // panics if slice is empty
1299 for _, v := range s[1:] {
1300 if v < r {
1301 r = v
1302 }
1303 }
1304 return r
1305}
1306```
1307
1308#### Conjunction and disjunction in contracts
1309
1310The use of comma to separate types is a general mechanism.
1311A contract can be considered as a set of constraints, where the
1312constraints are either methods or types.
1313Separating constraints by a semicolon or newline means that the
1314constraints are a conjunction: each constraint must be satisfied.
1315Separating constraints by a comma means that the constraints are a
1316disjunction: at least one of the constraints must be satisified.
1317
1318With a conjunction of constraints in a contract, a generic function
1319may use any operation permitted by at least one of the constraints.
1320With a disjunction, a generic function may use any operation permitted
1321by all of the constraints.
1322
1323Syntactically, the type parameter being constrained must be listed for
1324each individual conjunction constraint, but only once for the
1325disjunction constraints.
1326
1327Normally methods will be listed as a conjunction, separated by a
1328semicolon or newline.
1329
1330```Go
1331// PrintStringer1 and PrintStringer2 are equivalent.
1332contract PrintStringer1(T) {
1333 T String() string
1334 T Print()
1335}
1336
1337contract PrintStringer2(T) {
1338 T String() string; T Print()
1339}
1340```
1341
1342Normally builtin types will be listed as a disjunction, separated by
1343commas.
1344
1345```Go
1346contract Float(T) {
1347 T float32, float64
1348}
1349```
1350
1351However, this is not required.
1352For example:
1353
1354```Go
1355contract IOCloser(S) {
1356 S Read([]byte) (int, error), // note trailing comma
1357 Write([]byte) (int, error)
1358 S Close() error
1359}
1360```
1361
1362This contract accepts any type that has a `Close` method and also has
1363either a `Read` or a `Write` method (or both).
1364To put it another way, it accepts any type that implements either
1365`io.ReadCloser` or `io.WriteCloser` (or both).
1366In a generic function using this contract permits calling the
1367`Close` method, but calling the `Read` or `Write` method requires a
1368type assertion to an interface type.
1369It's not clear whether this is useful, but it is valid.
1370
1371Another, pedantic, example:
1372
1373```Go
1374contract unsatisfiable(T) {
1375 T int
1376 T uint
1377}
1378```
1379
1380This contract permits any type that is both `int` and `uint`.
1381Since there is no such type, the contract does not permit any type.
1382This is valid but useless.
1383
1384#### Both types and methods in contracts
1385
1386A contract may list both builtin types and methods, typically using
1387conjunctions and disjunctions as follows:
1388
1389```Go
1390contract StringableSignedInteger(T) {
1391 T int, int8, int16, int32, int64
1392 T String() string
1393}
1394```
1395
1396This contract permits any type defined as one of the listed types,
1397provided it also has a `String() string` method.
1398Although the `StringableSignedInteger` contract explicitly lists
1399`int`, the type `int` is not permitted as a type argument, since `int`
1400does not have a `String` method.
1401An example of a type argument that would be permitted is `MyInt`,
1402defined as:
1403
1404```Go
1405type MyInt int
1406func (mi MyInt) String() string {
1407 return fmt.Sprintf("MyInt(%d)", mi)
1408}
1409```
1410
1411#### Aggregate types in contracts
1412
1413A type in a contract need not be a predeclared type; it can be a type
1414literal composed of predeclared types.
1415
1416```Go
1417contract byteseq(T) {
1418 T string, []byte
1419}
1420```
1421
1422The same rules apply.
1423The type argument for this contract may be `string` or `[]byte` or a
1424type whose underlying type is one of those.
1425A parameterized function with this contract may use any operation
1426permitted by both `string` and `[]byte`.
1427
1428Given these definitions
1429
1430```Go
1431type MyByte byte
1432type MyByteAlias = byte
1433```
1434
1435the `byteseq` contract is satisfied by any of `string`, `[]byte`,
1436`[]MyByte`, `[]MyByteAlias`.
1437
1438The `byteseq` contract permits writing generic functions that work
1439for either `string` or `[]byte` types.
1440
1441```Go
1442func Join(type T byteseq)(a []T, sep T) (ret T) {
1443 if len(a) == 0 {
1444 // Use the result parameter as a zero value;
1445 // see discussion of zero value below.
1446 return ret
1447 }
1448 if len(a) == 1 {
1449 return T(append([]byte(nil), a[0]...))
1450 }
1451 n := len(sep) * (len(a) - 1)
1452 for i := 0; i < len(a); i++ {
1453 n += len(a[i]) // len works for both string and []byte
1454 }
Andrew Bonventred41bf0f2019-07-29 16:25:31 -04001455
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001456 b := make([]byte, n)
1457 bp := copy(b, a[0])
1458 for _, s := range a[1:] {
1459 bp += copy(b[bp:], sep)
1460 bp += copy(b[bp:], s)
1461 }
1462 return T(b)
1463}
1464```
1465
Ian Lance Taylorca869dd2019-07-31 10:30:47 -07001466#### Aggregates of type parameters in contracts
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001467
1468A type literal in a contract can refer not only to predeclared types,
1469but also to type parameters.
1470In this example, the `Slice` contract takes two parameters.
1471The first type parameter is required to be a slice of the second.
1472There are no constraints on the second type parameter.
1473
1474```Go
1475contract Slice(S, Element) {
1476 S []Element
1477}
1478```
1479
1480We can use the `Slice` contract to define a function that takes an
1481argument of a slice type and returns a result of that same type.
1482
1483```Go
Ian Lance Taylorca869dd2019-07-31 10:30:47 -07001484func Map(type S, Element Slice)(s S, f func(Element) Element) S {
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001485 r := make(S, len(s))
1486 for i, v := range s {
Ian Lance Taylorca869dd2019-07-31 10:30:47 -07001487 r[i] = f(v)
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001488 }
1489 return r
1490}
1491
1492type MySlice []int
1493
1494func DoubleMySlice(s MySlice) MySlice {
1495 v := Map(MySlice, int)(s, func(e int) int { return 2 * e })
1496 // Here v has type MySlice, not type []int.
1497 return v
1498}
1499```
1500
1501(Note: the type inference rules described above do not permit
1502inferring both `MySlice` and `int` when `DoubleMySlice` calls `Map`.
1503It may be worth extending them, to make it easier to use functions
1504that are careful to return the same result type as input type.
1505Similarly, we would consider extending the type inference rules to
1506permit inferring the type `Edge` from the type `Node` in the
1507`graph.New` example shown earlier.)
1508
Ian Lance Taylorca869dd2019-07-31 10:30:47 -07001509To avoid a parsing ambiguity, when a type literal in a contract refers
1510to a parameterized type, extra parentheses are required, so that it is
1511not confused with a method.
1512
1513```Go
1514type M(type T) []T
1515
1516contract C(T) {
1517 T M(T) // T must implement the method M with an argument of type T
1518 T (M(T)) // T must be the type M(T)
1519}
1520```
1521
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001522#### Comparable types in contracts
1523
1524Earlier we mentioned that there are two exceptions to the rule that
1525operators may only be used with types that are predeclared by the
1526language.
1527The exceptions are `==` and `!=`, which are permitted for struct,
1528array, and interface types.
1529These are useful enough that we want to be able to write a contract
1530that accepts any comparable type.
1531
1532To do this we introduce a new predeclared contract: `comparable`.
1533The `comparable` contract takes a single type parameter.
1534It accepts as a type argument any comparable type.
1535It permits in a parameterized function the use of `==` and `!=` with
1536values of that type parameter.
1537
1538As a predeclared contract, `comparable` may be used in a function or
1539type definition, or it may be embedded in another contract.
1540
1541For example, this function may be instantiated with any comparable
1542type:
1543
1544```Go
1545func Index(type T comparable)(s []T, x T) int {
1546 for i, v := range s {
1547 if v == x {
1548 return i
1549 }
1550 }
1551 return -1
1552}
1553```
1554
1555#### Observations on types in contracts
1556
1557It may seem awkward to explicitly list types in a contract, but it is
1558clear both as to which type arguments are permitted at the call site,
1559and which operations are permitted by the parameterized function.
1560
1561If the language later changes to support operator methods (there are
1562no such plans at present), then contracts will handle them as they do
1563any other kind of method.
1564
1565There will always be a limited number of predeclared types, and a
1566limited number of operators that those types support.
1567Future language changes will not fundamentally change those facts, so
1568this approach will continue to be useful.
1569
1570This approach does not attempt to handle every possible operator.
1571For example, there is no way to usefully express the struct field
1572reference `.` or the general index operator `[]`.
1573The expectation is that those will be handled using aggregate types in
1574a parameterized function definition, rather than requiring aggregate
1575types as a type argument.
1576For example, we expect functions that want to index into a slice to be
1577parameterized on the slice element type `T`, and to use parameters or
1578variables of type `[]T`.
1579
1580As shown in the `DoubleMySlice` example above, this approach makes it
1581awkward to write generic functions that accept and return an aggregate
1582type and want to return the same result type as their argument type.
1583Defined aggregate types are not common, but they do arise.
1584This awkwardness is a weakness of this approach.
Russ Cox00fd2f62018-08-23 15:11:30 -04001585
1586#### Type conversions
1587
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001588In a function with two type parameters `From` and `To`, a value of
1589type `From` may be converted to a value of type `To` if all the
1590types accepted by `From`'s contract can be converted to all the
1591types accepted by `To`'s contract.
1592If either type parameter does not accept types, then type conversions
1593are not permitted.
Russ Cox00fd2f62018-08-23 15:11:30 -04001594
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001595For example:
Russ Cox00fd2f62018-08-23 15:11:30 -04001596
1597```Go
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001598contract integer(T) {
1599 T int, int8, int16, int32, int64,
1600 uint, uint8, uint16, uint32, uint64, uintptr
Russ Cox00fd2f62018-08-23 15:11:30 -04001601}
1602
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001603contract integer2(T1, T2) {
1604 integer(T1)
1605 integer(T2)
1606}
Andrew Bonventred41bf0f2019-07-29 16:25:31 -04001607
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001608func Convert(type To, From integer2)(from From) To {
Russ Cox00fd2f62018-08-23 15:11:30 -04001609 to := To(from)
1610 if From(to) != from {
1611 panic("conversion out of range")
1612 }
1613 return to
1614}
1615```
1616
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001617The type conversions in `Convert` are permitted because Go permits
1618every integer type to be converted to every other integer type.
Russ Cox00fd2f62018-08-23 15:11:30 -04001619
1620#### Untyped constants
1621
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001622Some functions use untyped constants.
1623An untyped constant is permitted with a value of some type parameter
1624if it is permitted with every type accepted by the type parameter's
1625contract.
Russ Cox00fd2f62018-08-23 15:11:30 -04001626
1627```Go
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001628contract integer(T) {
1629 T int, int8, int16, int32, int64,
1630 uint, uint8, uint16, uint32, uint64, uintptr
Russ Cox00fd2f62018-08-23 15:11:30 -04001631}
1632
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001633func Add10(type T integer)(s []T) {
Russ Cox00fd2f62018-08-23 15:11:30 -04001634 for i, v := range s {
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001635 s[i] = v + 10 // OK: 10 can convert to any integer type
1636 }
1637}
1638
1639// This function is INVALID.
1640func Add1024(type T integer)(s []T) {
1641 for i, v := range s {
1642 s[i] = v + 1024 // INVALID: 1024 not permitted by int8/uint8
Russ Cox00fd2f62018-08-23 15:11:30 -04001643 }
1644}
1645```
1646
Russ Cox00fd2f62018-08-23 15:11:30 -04001647### Implementation
1648
1649Russ Cox [famously observed](https://research.swtch.com/generic) that
1650generics require choosing among slow programmers, slow compilers, or
1651slow execution times.
1652
1653We believe that this design permits different implementation choices.
1654Code may be compiled separately for each set of type arguments, or it
1655may be compiled as though each type argument is handled similarly to
1656an interface type with method calls, or there may be some combination
1657of the two.
1658
1659In other words, this design permits people to stop choosing slow
1660programmers, and permits the implementation to decide between slow
1661compilers (compile each set of type arguments separately) or slow
1662execution times (use method calls for each operation on a value of a
1663type argument).
1664
1665### Summary
1666
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001667While this document is long and detailed, the actual design reduces to
1668a few major points.
Russ Cox00fd2f62018-08-23 15:11:30 -04001669
1670* Functions and types can have type parameters, which are defined
1671 using optional contracts.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001672* Contracts describe the methods required and the builtin types
1673 permitted for a type argument.
1674* Contracts describe the methods and operations permitted for a type
1675 parameter.
1676* Type inference will often permit omitting type arguments when
Russ Cox00fd2f62018-08-23 15:11:30 -04001677 calling functions with type parameters.
1678
1679This design is completely backward compatible, in that any valid Go 1
1680program will still be valid if this design is adopted (assuming
1681`contract` is treated as a pseudo-keyword that is only meaningful at
1682top level).
1683
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001684We believe that this design addresses people's needs for generic
Russ Cox00fd2f62018-08-23 15:11:30 -04001685programming in Go, without making the language any more complex than
1686necessary.
1687
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001688We can't truly know the impact on the language without years of
Russ Cox00fd2f62018-08-23 15:11:30 -04001689experience with this design.
1690That said, here are some speculations.
1691
1692#### Complexity
1693
1694One of the great aspects of Go is its simplicity.
1695Clearly this design makes the language more complex.
1696
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001697We believe that the increased complexity is small for people reading
1698well written generic code, rather than writing it.
Russ Cox00fd2f62018-08-23 15:11:30 -04001699Naturally people must learn the new syntax for declaring type
1700parameters.
1701The code within a generic function reads like ordinary Go code, as can
1702be seen in the examples below.
1703It is an easy shift to go from `[]int` to `[]T`.
1704Type parameter contracts serve effectively as documentation,
1705describing the type.
1706
1707We expect that most people will not write generic code themselves, but
1708many people are likely to write packages that use generic code written
1709by others.
1710In the common case, generic functions work exactly like non-generic
1711functions: you simply call them.
1712Type inference means that you do not have to write out the type
1713arguments explicitly.
1714The type inference rules are designed to be unsurprising: either the
1715type arguments are deduced correctly, or the call fails and requires
1716explicit type parameters.
1717Type inference uses type identity, with no attempt to resolve two
1718types that are similar but not identical, which removes significant
1719complexity.
1720
1721People using generic types will have to pass explicit type arguments.
1722The syntax for this is familiar.
1723The only change is passing arguments to types rather than only to
1724functions.
1725
Russ Cox00fd2f62018-08-23 15:11:30 -04001726In general, we have tried to avoid surprises in the design.
1727Only time will tell whether we succeeded.
1728
1729#### Pervasiveness
1730
1731We expect that a few new packages will be added to the standard
1732library.
1733A new `slices` packages will be similar to the existing bytes and
1734strings packages, operating on slices of any element type.
1735New `maps` and `chans` packages will provide simple algorithms that
1736are currently duplicated for each element type.
1737A `set` package may be added.
1738
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001739A new `contracts` packages will provide standard embeddable contracts,
1740such as contracts that permit all integer types or all numeric types.
1741
Russ Cox00fd2f62018-08-23 15:11:30 -04001742Packages like `container/list` and `container/ring`, and types like
1743`sync.Map`, will be updated to be compile-time type-safe.
1744
1745The `math` package will be extended to provide a set of simple
1746standard algorithms for all numeric types, such as the ever popular
1747`Min` and `Max` functions.
1748
1749It is likely that new special purpose compile-time type-safe container
1750types will be developed, and some may become widely used.
1751
1752We do not expect approaches like the C++ STL iterator types to become
1753widely used.
1754In Go that sort of idea is more naturally expressed using an interface
1755type.
1756In C++ terms, using an interface type for an iterator can be seen as
1757carrying an abstraction penalty, in that run-time efficiency will be
1758less than C++ approaches that in effect inline all code; we believe
1759that Go programmers will continue to find that sort of penalty to be
1760acceptable.
1761
1762As we get more container types, we may develop a standard `Iterator`
1763interface.
1764That may in turn lead to pressure to modify the language to add some
1765mechanism for using an `Iterator` with the `range` clause.
1766That is very speculative, though.
1767
1768#### Efficiency
1769
1770It is not clear what sort of efficiency people expect from generic
1771code.
1772
1773Generic functions, rather than generic types, can probably be compiled
1774using an interface-based approach.
1775That will optimize compile time, in that the package is only compiled
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001776once, but there will be some run time cost.
Russ Cox00fd2f62018-08-23 15:11:30 -04001777
1778Generic types may most naturally be compiled multiple times for each
1779set of type arguments.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001780This will clearly carry a compile time cost, but there shouldn't be
1781any run time cost.
Russ Cox00fd2f62018-08-23 15:11:30 -04001782Compilers can also choose to implement generic types similarly to
1783interface types, using special purpose methods to access each element
1784that depends on a type parameter.
1785
1786Only experience will show what people expect in this area.
1787
1788#### Omissions
1789
1790We believe that this design covers the basic requirements for
1791generic programming.
1792However, there are a number of programming constructs that are not
1793supported.
1794
1795* No specialization.
1796 There is no way to write multiple versions of a generic function
1797 that are designed to work with specific type arguments (other than
1798 using type assertions or type switches).
1799* No metaprogramming.
1800 There is no way to write code that is executed at compile time to
1801 generate code to be executed at run time.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001802* No higher level abstraction.
Russ Cox00fd2f62018-08-23 15:11:30 -04001803 There is no way to speak about a function with type arguments other
1804 than to call it or instantiate it.
1805 There is no way to speak about a parameterized type other than to
1806 instantiate it.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001807* No general type description.
1808 For operator support contracts use specific types, rather than
1809 describing the characteristics that a type must have.
1810 This is easy to understand but may be limiting at times.
Russ Cox00fd2f62018-08-23 15:11:30 -04001811* No covariance or contravariance.
1812* No operator methods.
1813 You can write a generic container that is compile-time type-safe,
1814 but you can only access it with ordinary methods, not with syntax
1815 like `c[k]`.
1816 Similarly, there is no way to use `range` with a generic container
1817 type.
1818* No currying.
1819 There is no way to specify only some of the type arguments, other
1820 than by using a type alias or a helper function.
1821* No adaptors.
1822 There is no way for a contract to define adaptors that could be used
1823 to support type arguments that do not already satisfy the contract,
1824 such as, for example, defining an `==` operator in terms of an
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001825 `Equal` method, or vice-versa.
fREW Schmidtb347d162019-07-29 21:19:28 +00001826* No parameterization on non-type values such as constants.
Russ Cox00fd2f62018-08-23 15:11:30 -04001827 This arises most obviously for arrays, where it might sometimes be
1828 convenient to write `type Matrix(type n int) [n][n]float64`.
1829 It might also sometimes be useful to specify significant values for
1830 a container type, such as a default value for elements.
1831
1832#### Issues
1833
1834There are some issues with this design that deserve a more detailed
1835discussion.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001836We think these issues are relatively minor compared to the design as a
1837whole, but they still deserve a complete hearing and discussion.
Russ Cox00fd2f62018-08-23 15:11:30 -04001838
1839##### The zero value
1840
1841This design has no simple expression for the zero value of a type
1842parameter.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001843For example, consider this implementation of optional values that uses
Russ Cox00fd2f62018-08-23 15:11:30 -04001844pointers:
1845
1846```Go
1847type Optional(type T) struct {
1848 p *T
1849}
1850
1851func (o Optional(T)) Val() T {
1852 if o.p != nil {
1853 return *o.p
1854 }
1855 var zero T
1856 return zero
1857}
1858```
1859
1860In the case where `o.p == nil`, we want to return the zero value of
1861`T`, but we have no way to write that.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001862It would be nice to be able to write `return nil`, but that wouldn't
Russ Cox00fd2f62018-08-23 15:11:30 -04001863work if `T` is, say, `int`; in that case we would have to write
1864`return 0`.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001865And, of course, there is no contract to support either `return nil` or
1866`return 0`.
Russ Cox00fd2f62018-08-23 15:11:30 -04001867
1868Some approaches to this are:
1869
1870* Use `var zero T`, as above, which works with the existing design
1871 but requires an extra statement.
1872* Use `*new(T)`, which is ugly but works with the existing design.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001873* For results only, name the result parameter `_`, and use a naked
1874 `return` statement to return the zero value.
Russ Cox00fd2f62018-08-23 15:11:30 -04001875* Extend the design to permit using `nil` as the zero value of any
1876 generic type (but see [issue 22729](https://golang.org/issue/22729)).
1877* Extend the design to permit using `T{}`, where `T` is a type
1878 parameter, to indicate the zero value of the type.
1879* Change the language to permit using `_` on the right hand of an
1880 assignment (including `return` or a function call) as proposed in
1881 [issue 19642](https://golang.org/issue/19642).
1882
1883We feel that more experience with this design is needed before
1884deciding what, if anything, to do here.
1885
1886##### Lots of irritating silly parentheses
1887
1888Calling a function with type parameters requires an additional list of
1889type arguments if the type arguments can not be inferred.
1890If the function returns a function, and we call that, we get still
1891more parentheses.
1892
1893```Go
1894 F(int, float64)(x, y)(s)
1895```
1896
1897We experimented with other syntaxes, such as using a colon to separate
1898the type arguments from the regular arguments.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001899The current design seems to be the nicest, but perhaps something
Russ Cox00fd2f62018-08-23 15:11:30 -04001900better is possible.
1901
Russ Cox00fd2f62018-08-23 15:11:30 -04001902##### Pointer vs. value methods in contracts
1903
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001904Contracts do not provide a way to distinguish between pointer and
1905value methods, so types that provide either will satisfy a contract.
1906This in turn requires that parameterized functions always permit
1907either kind of method.
1908This may be confusing, in that a parameterized function may invoke a
1909pointer method on a temporary value; if the pointer method changes the
1910value to which the receiver points, those changes will be lost.
Russ Cox00fd2f62018-08-23 15:11:30 -04001911We will have to judge from experience how much this confuses people in
1912practice.
1913
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001914##### Defined aggregate types
Russ Cox00fd2f62018-08-23 15:11:30 -04001915
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001916As discussed above, an extra type parameter is required for a function
1917to take, as an argument, a defined type whose underlying type is an
1918aggregate type, and to return the same defined type as a result.
Russ Cox00fd2f62018-08-23 15:11:30 -04001919
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07001920For example, this function will map a function across a slice.
1921
1922```Go
1923func Map(type Element)(s []Element, f func(Element) Element) []Element {
1924 r := make([]Element, len(s))
1925 for i, v := range s {
1926 r[i] = f(v)
1927 }
1928 return r
1929}
1930```
1931
1932However, when called on a defined type, it will return a slice of the
1933element type of that type, rather than the defined type itself.
1934
1935```Go
1936type MySlice []int
1937
1938func DoubleMySlice(s MySlice) MySlice {
1939 s2 := Map(s, func(e int) int { return 2 * e })
1940 // Here s2 is type []int, not type MySlice.
1941 return MySlice(s2)
1942}
1943```
1944
1945As discussed above with an example, this can be avoided by using an
1946extra type parameter for `Map`, and using a contract that describes
1947the required relationship between the slice and element types.
1948This works but is awkward.
1949
1950##### Identifying the matched predeclared type
1951
1952In this design we suggest permitting type assertions and type switches
1953on values whose types are based on type parameters, but those type
1954assertions and switches would always test the actual type argument.
1955The design doesn't provide any way to test the contract type matched
1956by the type argument.
1957
1958Here is an example that shows the difference.
1959
1960```Go
1961contract Float(F) {
1962 F float32, float64
1963}
1964
1965func NewtonSqrt(type F Float)(v F) F {
1966 var iterations int
1967 switch v.(type) {
1968 case float32:
1969 iterations = 4
1970 case float64:
1971 iterations = 5
1972 default:
1973 panic(fmt.Sprintf("unexpected type %T", v))
1974 }
1975 // Code omitted.
1976}
1977
1978type MyFloat float32
1979
1980var G = NewtonSqrt(MyFloat(64))
1981```
1982
1983This code will panic when initializing `G`, because the type of `v` in
1984the `NewtonSqrt` function will be `MyFloat`, not `float32` or
1985`float64`.
1986What this function actually wants to test is not the type of `v`, but
1987the type that `v` matched in the contract.
1988
1989One way to handle this would be to permit type switches on the type
1990`F`, rather than the value `v`, with the proviso that the type `F`
1991would always match a type defined in the contract.
1992This kind of type switch would only be permitted if the contract does
1993list explicit types, and only types listed in the contract would be
1994permitted as cases.
1995
1996If we took this approach, we would stop permitting type assertions and
1997switches on values whose type is based on a type parameter.
1998Those assertions and switches can always be done by first converting
1999the value to the empty interface type.
2000
2001A different approach would be that if a contract specifies any types
2002for a type parameter, then let type switches and assertions on values
2003whose type is, or is based on, that type parameter to match only the
2004types listed in the type parameter's contract.
2005It is still possible to match the value's actual type by first
2006converting it to the `interface{}` type and then doing the type
2007assertion or switch.
Russ Cox00fd2f62018-08-23 15:11:30 -04002008
2009#### Discarded ideas
2010
2011This design is not perfect, and it will be changed as we gain
2012experience with it.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002013That said, there are many ideas that we've already considered in
Russ Cox00fd2f62018-08-23 15:11:30 -04002014detail.
2015This section lists some of those ideas in the hopes that it will help
2016to reduce repetitive discussion.
2017The ideas are presented in the form of a FAQ.
2018
2019##### Why not use interfaces instead of contracts?
2020
2021_The interface method syntax is familiar._
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002022_Why introduce another way to write methods?_
2023
2024Contracts, unlike interfaces, support multiple types, including
2025describing ways that the types refer to each other.
Russ Cox00fd2f62018-08-23 15:11:30 -04002026
2027It is unclear how to represent operators using interface methods.
2028We considered syntaxes like `+(T, T) T`, but that is confusing and
2029repetitive.
2030Also, a minor point, but `==(T, T) bool` does not correspond to the
2031`==` operator, which returns an untyped boolean value, not `bool`.
2032We also considered writing simply `+` or `==`.
2033That seems to work but unfortunately the semicolon insertion rules
2034require writing a semicolon after each operator at the end of a line.
2035Using contracts that look like functions gives us a familiar syntax at
2036the cost of some repetition.
2037These are not fatal problems, but they are difficulties.
2038
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002039More seriously, a contract is a relationship between the definition of
2040a generic function and the callers of that function.
2041To put it another way, it is a relationship between a set of type
2042parameters and a set of type arguments.
2043The contract defines how values of the type parameters may be used,
2044and defines the requirements on the type arguments.
2045That is why it is called a contract: because it defines the behavior
2046on both sides.
2047
2048An interface is a type, not a relationship between function
2049definitions and callers.
2050A program can have a value of an interface type, but it makes no sense
2051to speak of a value of a contract type.
2052A value of interface type has both a static type (the interface type)
2053and a dynamic type (some non-interface type), but there is no similar
2054concept for contracts.
2055
2056In other words, contracts are not extensions of interface types.
2057There are things you can do with a contract that you cannot do with an
2058interface type, and there are things you can do with an interace type
2059that you cannot do with a contract.
2060
2061It is true that a contract that has a single type parameter and that
2062lists only methods, not builtin types, for that type parameter, looks
2063similar to an interface type.
2064But all the similarity amounts to is that both provide a list of
2065methods.
2066We could consider permitting using an interface type as a contract
2067with a single type parameter that lists only methods.
2068But that should not mislead us into thinking that contracts are
2069interfaces.
2070
2071##### Why not permit contracts to describe a type?
2072
2073_In order to use operators contracts have to explicitly and tediously_
2074_list types._
2075_Why not permit them to describe a type?_
2076
2077There are many different ways that a Go type can be used.
2078While it is possible to invent notation to describe the various
2079operations in a contract, it leads to a proliferation of additional
2080syntactic constructs, making contracts complicated and hard to read.
2081The approach used in this design is simpler and relies on only a few
2082new syntactic constructs and names.
2083
Russ Cox00fd2f62018-08-23 15:11:30 -04002084##### Why not put type parameters on packages?
2085
2086We investigated this extensively.
2087It becomes problematic when you want to write a `list` package, and
2088you want that package to include a `Transform` function that converts
2089a `List` of one element type to a `List` of another element type.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002090It's very awkward for a function in one instantiation of a package to
Russ Cox00fd2f62018-08-23 15:11:30 -04002091return a type that requires a different instantiation of the package.
2092
2093It also confuses package boundaries with type definitions.
2094There is no particular reason to think that the uses of parameterized
2095types will break down neatly into packages.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002096Sometimes they will, sometimes they won't.
Russ Cox00fd2f62018-08-23 15:11:30 -04002097
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002098##### Why not use the syntax `F<T>` like C++ and Java?
Russ Cox00fd2f62018-08-23 15:11:30 -04002099
2100When parsing code within a function, such as `v := F<T>`, at the point
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002101of seeing the `<` it's ambiguous whether we are seeing a type
Russ Cox00fd2f62018-08-23 15:11:30 -04002102instantiation or an expression using the `<` operator.
2103Resolving that requires effectively unbounded lookahead.
2104In general we strive to keep the Go parser simple.
2105
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002106##### Why not use the syntax `F[T]`?
Russ Cox00fd2f62018-08-23 15:11:30 -04002107
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002108When parsing a type declaration `type A [T] int` it's ambiguous
Russ Cox00fd2f62018-08-23 15:11:30 -04002109whether this is a parameterized type defined (uselessly) as `int` or
2110whether it is an array type with `T` elements.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002111However, this would be addressed by requiring `type A [type T] int`
2112for a parameterized type.
2113
2114Parsing declarations like `func f(A[T]int)` (a single parameter of
2115type `[T]int`) and `func f(A[T], int)` (two parameters, one of type
2116`A[T]` and one of type `int`) show that some additional parsing
2117lookahead is required.
2118This is solvable but adds parsing complexity.
2119
2120The language generally permits a trailing comma in a comma-separated
2121list, so `A[T,]` should be permitted if `A` is a parameterized type,
2122but normally would not be permitted for an index expression.
2123However, the parser can't know whether `A` is a parameterized type or
2124a value of slice, array, or map type, so this parse error can not be
2125reported until after type checking is complete.
2126Again, solvable but complicated.
2127
2128More generally, we felt that the square brackets were too intrusive on
2129the page and that parentheses were more Go like.
2130We will reevaluate this decision as we gain more experience.
Russ Cox00fd2f62018-08-23 15:11:30 -04002131
2132##### Why not use `F«T»`?
2133
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002134We considered it but we couldn't bring ourselves to require
Russ Cox00fd2f62018-08-23 15:11:30 -04002135non-ASCII.
2136
2137##### Why not define contracts in a standard package?
2138
2139_Instead of writing out contracts, use names like_
2140_`contracts.Arithmetic` and `contracts.Comparable`._
2141
2142Listing all the possible combinations of types gets rather lengthy.
2143It also introduces a new set of names that not only the writer of
2144generic code, but, more importantly, the reader, must remember.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002145One of the driving goals of this design is to introduce as few new
2146names as possible.
2147In this design we introduce one new keyword and one new predefined
2148name.
Russ Cox00fd2f62018-08-23 15:11:30 -04002149
2150We expect that if people find such names useful, we can introduce a
2151package `contracts` that defines the useful names in the form of
2152contracts that can be used by other types and functions and embedded
2153in other contracts.
2154
2155#### Comparison with Java
2156
2157Most complaints about Java generics center around type erasure.
2158This design does not have type erasure.
2159The reflection information for a generic type will include the full
2160compile-time type information.
2161
2162In Java type wildcards (`List<? extends Number>`, `List<? super
2163Number>`) implement covariance and contravariance.
2164These concepts are missing from Go, which makes generic types much
2165simpler.
2166
2167#### Comparison with C++
2168
2169C++ templates do not enforce any constraints on the type arguments
2170(unless the concept proposal is adopted).
2171This means that changing template code can accidentally break far-off
2172instantiations.
2173It also means that error messages are reported only at instantiation
2174time, and can be deeply nested and difficult to understand.
2175This design avoids these problems through explicit contracts.
2176
2177C++ supports template metaprogramming, which can be thought of as
2178ordinary programming done at compile time using a syntax that is
2179completely different than that of non-template C++.
2180This design has no similar feature.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002181This saves considerable complexity while losing some power and run
2182time efficiency.
Russ Cox00fd2f62018-08-23 15:11:30 -04002183
2184### Examples
2185
2186The following sections are examples of how this design could be used.
2187This is intended to address specific areas where people have created
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002188user experience reports concerned with Go's lack of generics.
Russ Cox00fd2f62018-08-23 15:11:30 -04002189
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002190#### Sort
Russ Cox00fd2f62018-08-23 15:11:30 -04002191
2192Before the introduction of `sort.Slice`, a common complaint was the
2193need for boilerplate definitions in order to use `sort.Sort`.
2194With this design, we can add to the sort package as follows:
2195
2196```Go
Ian Lance Taylorca869dd2019-07-31 10:30:47 -07002197type orderedSlice(type Elem Ordered) []Elem
Russ Cox00fd2f62018-08-23 15:11:30 -04002198
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002199func (s orderedSlice(Elem)) Len() int { return len(s) }
2200func (s orderedSlice(Elem)) Less(i, j int) bool { return s[i] < s[j] }
2201func (s orderedSlice(Elem)) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
Russ Cox00fd2f62018-08-23 15:11:30 -04002202
2203// OrderedSlice sorts the slice s in ascending order.
2204// The elements of s must be ordered using the < operator.
Ian Lance Taylorca869dd2019-07-31 10:30:47 -07002205func OrderedSlice(type Elem Ordered)(s []Elem) {
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002206 sort.Sort(orderedSlice(Elem)(s))
Russ Cox00fd2f62018-08-23 15:11:30 -04002207}
2208```
2209
2210Now we can write:
2211
2212```Go
2213 sort.OrderedSlice(int32)([]int32{3, 5, 2})
2214```
2215
2216We can rely on type inference to omit the type argument list:
2217
2218```Go
2219 sort.OrderedSlice([]string{"a", "c", "b"})
2220```
2221
2222Along the same lines, we can add a function for sorting using a
2223comparison function, similar to `sort.Slice` but writing the function
2224to take values rather than slice indexes.
2225
2226```Go
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002227type sliceFn(type Elem) struct {
2228 s []Elem
2229 f func(Elem, Elem) bool
Russ Cox00fd2f62018-08-23 15:11:30 -04002230}
2231
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002232func (s sliceFn(Elem)) Len() int { return len(s.s) }
2233func (s sliceFn(Elem)) Less(i, j int) bool { return s.f(s.s[i], s.s[j]) }
2234func (s sliceFn(Elem)) Swap(i, j int) { s.s[i], s.s[j] = s.s[j], s.s[i] }
Russ Cox00fd2f62018-08-23 15:11:30 -04002235
2236// SliceFn sorts the slice s according to the function f.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002237func SliceFn(type Elem)(s []Elem, f func(Elem, Elem) bool) {
2238 Sort(sliceFn(Elem){s, f})
Russ Cox00fd2f62018-08-23 15:11:30 -04002239}
2240```
2241
2242An example of calling this might be:
2243
2244```Go
2245 var s []*Person
2246 // ...
2247 sort.SliceFn(s, func(p1, p2 *Person) bool { return p1.Name < p2.Name })
2248```
2249
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002250#### Map keys
Russ Cox00fd2f62018-08-23 15:11:30 -04002251
2252Here is how to get a slice of the keys of any map.
2253
2254```Go
2255package maps
2256
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002257// Keys returns the keys of the map m.
2258// Note that map keys (here called type K) must be comparable.
2259func Keys(type K, V comparable(K))(m map[K]V) []K {
Russ Cox00fd2f62018-08-23 15:11:30 -04002260 r := make([]K, 0, len(m))
2261 for k := range m {
2262 r = append(r, k)
2263 }
2264 return r
2265}
2266```
2267
2268In typical use the types will be inferred.
2269
2270```Go
2271 k := maps.Keys(map[int]int{1:2, 2:4}) // sets k to []int{1, 2} (or {2, 1})
2272```
2273
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002274#### Map/Reduce/Filter
Russ Cox00fd2f62018-08-23 15:11:30 -04002275
2276Here is an example of how to write map, reduce, and filter functions
2277for slices.
2278These functions are intended to correspond to the similar functions in
2279Lisp, Python, Java, and so forth.
2280
2281```Go
2282// Package slices implements various slice algorithms.
2283package slices
2284
2285// Map turns a []T1 to a []T2 using a mapping function.
2286func Map(type T1, T2)(s []T1, f func(T1) T2) []T2 {
2287 r := make([]T2, len(s))
2288 for i, v := range s {
2289 r[i] = f(v)
2290 }
2291 return r
2292}
2293
2294// Reduce reduces a []T1 to a single value using a reduction function.
2295func Reduce(type T1, T2)(s []T1, initializer T2, f func(T2, T1) T2) T2 {
2296 r := initializer
2297 for _, v := range s {
2298 r = f(r, v)
2299 }
2300 return r
2301}
2302
2303// Filter filters values from a slice using a filter function.
2304func Filter(type T)(s []T, f func(T) bool) []T {
2305 var r []T
2306 for _, v := range s {
2307 if f(v) {
2308 r = append(r, v)
2309 }
2310 }
2311 return r
2312}
2313```
2314
2315Example calls:
2316
2317```Go
2318 s := []int{1, 2, 3}
2319 floats := slices.Map(s, func(i int) float64 { return float64(i) })
2320 sum := slices.Reduce(s, 0, func(i, j int) int { return i + j })
2321 evens := slices.Filter(s, func(i int) bool { return i%2 == 0 })
2322```
2323
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002324#### Sets
Russ Cox00fd2f62018-08-23 15:11:30 -04002325
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002326Many people have asked for Go's builtin map type to be extended, or
Russ Cox00fd2f62018-08-23 15:11:30 -04002327rather reduced, to support a set type.
2328Here is a type-safe implementation of a set type, albeit one that uses
2329methods rather than operators like `[]`.
2330
2331```Go
2332// Package set implements sets of any type.
2333package set
2334
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002335type Set(type Elem comparable) map[Elem]struct{}
Russ Cox00fd2f62018-08-23 15:11:30 -04002336
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002337func Make(type Elem comparable)() Set(Elem) {
2338 return make(Set(Elem))
Russ Cox00fd2f62018-08-23 15:11:30 -04002339}
2340
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002341func (s Set(Elem)) Add(v Elem) {
Russ Cox00fd2f62018-08-23 15:11:30 -04002342 s[v] = struct{}{}
2343}
2344
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002345func (s Set(Elem)) Delete(v Elem) {
Russ Cox00fd2f62018-08-23 15:11:30 -04002346 delete(s, v)
2347}
2348
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002349func (s Set(Elem)) Contains(v Elem) bool {
Russ Cox00fd2f62018-08-23 15:11:30 -04002350 _, ok := s[v]
2351 return ok
2352}
2353
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002354func (s Set(Elem)) Len() int {
Russ Cox00fd2f62018-08-23 15:11:30 -04002355 return len(s)
2356}
2357
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002358func (s Set(Elem)) Iterate(f func(Elem)) {
Russ Cox00fd2f62018-08-23 15:11:30 -04002359 for v := range s {
2360 f(v)
2361 }
2362}
2363```
2364
2365Example use:
2366
2367```Go
Alec Benzerded804a2019-12-11 15:39:41 +00002368 s := set.Make(int)()
Russ Cox00fd2f62018-08-23 15:11:30 -04002369 s.Add(1)
2370 if s.Contains(2) { panic("unexpected 2") }
2371```
2372
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002373This example, like the sort examples above, show how to use this
Russ Cox00fd2f62018-08-23 15:11:30 -04002374design to provide a compile-time type-safe wrapper around an
2375existing API.
2376
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002377#### Channels
Russ Cox00fd2f62018-08-23 15:11:30 -04002378
2379Many simple general purpose channel functions are never written,
2380because they must be written using reflection and the caller must type
2381assert the results.
2382With this design they become easy to write.
2383
2384```Go
2385package chans
2386
2387import "runtime"
2388
2389// Ranger returns a Sender and a Receiver. The Receiver provides a
2390// Next method to retrieve values. The Sender provides a Send method
2391// to send values and a Close method to stop sending values. The Next
2392// method indicates when the Sender has been closed, and the Send
2393// method indicates when the Receiver has been freed.
2394//
2395// This is a convenient way to exit a goroutine sending values when
2396// the receiver stops reading them.
2397func Ranger(type T)() (*Sender(T), *Receiver(T)) {
2398 c := make(chan T)
Gaal Yahas4a530da2018-09-01 19:44:20 +03002399 d := make(chan bool)
Russ Cox00fd2f62018-08-23 15:11:30 -04002400 s := &Sender(T){values: c, done: d}
2401 r := &Receiver(T){values: c, done: d}
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002402 runtime.SetFinalizer(r, r.finalize)
Russ Cox00fd2f62018-08-23 15:11:30 -04002403 return s, r
2404}
2405
2406// A sender is used to send values to a Receiver.
2407type Sender(type T) struct {
2408 values chan<- T
2409 done <-chan bool
2410}
2411
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002412// Send sends a value to the receiver. It returns whether any more
Russ Cox00fd2f62018-08-23 15:11:30 -04002413// values may be sent; if it returns false the value was not sent.
2414func (s *Sender(T)) Send(v T) bool {
2415 select {
2416 case s.values <- v:
2417 return true
2418 case <-s.done:
2419 return false
2420 }
2421}
2422
2423// Close tells the receiver that no more values will arrive.
2424// After Close is called, the Sender may no longer be used.
2425func (s *Sender(T)) Close() {
2426 close(s.values)
2427}
2428
2429// A Receiver receives values from a Sender.
2430type Receiver(type T) struct {
2431 values <-chan T
2432 done chan<- bool
2433}
2434
2435// Next returns the next value from the channel. The bool result
2436// indicates whether the value is valid, or whether the Sender has
2437// been closed and no more values will be received.
2438func (r *Receiver(T)) Next() (T, bool) {
2439 v, ok := <-r.values
2440 return v, ok
2441}
2442
2443// finalize is a finalizer for the receiver.
2444func (r *Receiver(T)) finalize() {
2445 close(r.done)
2446}
2447```
2448
2449There is an example of using this function in the next section.
2450
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002451#### Containers
Russ Cox00fd2f62018-08-23 15:11:30 -04002452
2453One of the frequent requests for generics in Go is the ability to
2454write compile-time type-safe containers.
2455This design makes it easy to write a compile-time type-safe wrapper
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002456around an existing container; we won't write out an example for that.
Russ Cox00fd2f62018-08-23 15:11:30 -04002457This design also makes it easy to write a compile-time type-safe
2458container that does not use boxing.
2459
2460Here is an example of an ordered map implemented as a binary tree.
2461The details of how it works are not too important.
2462The important points are:
2463
2464* The code is written in a natural Go style, using the key and value
2465 types where needed.
2466* The keys and values are stored directly in the nodes of the tree,
2467 not using pointers and not boxed as interface values.
2468
2469```Go
2470// Package orderedmap provides an ordered map, implemented as a binary tree.
2471package orderedmap
2472
2473import "chans"
2474
2475// Map is an ordered map.
2476type Map(type K, V) struct {
2477 root *node(K, V)
2478 compare func(K, K) int
2479}
2480
2481// node is the type of a node in the binary tree.
2482type node(type K, V) struct {
2483 key K
2484 val V
2485 left, right *node(K, V)
2486}
2487
2488// New returns a new map.
2489func New(type K, V)(compare func(K, K) int) *Map(K, V) {
2490 return &Map(K, V){compare: compare}
2491}
2492
2493// find looks up key in the map, and returns either a pointer
2494// to the node holding key, or a pointer to the location where
2495// such a node would go.
2496func (m *Map(K, V)) find(key K) **node(K, V) {
2497 pn := &m.root
2498 for *pn != nil {
2499 switch cmp := m.compare(key, (*pn).key); {
2500 case cmp < 0:
2501 pn = &(*pn).left
2502 case cmp > 0:
2503 pn = &(*pn).right
2504 default:
2505 return pn
2506 }
2507 }
2508 return pn
2509}
2510
2511// Insert inserts a new key/value into the map.
2512// If the key is already present, the value is replaced.
2513// Returns true if this is a new key, false if already present.
2514func (m *Map(K, V)) Insert(key K, val V) bool {
2515 pn := m.find(key)
2516 if *pn != nil {
2517 (*pn).val = val
2518 return false
2519 }
2520 *pn = &node(K, V){key: key, val: val}
2521 return true
2522}
2523
2524// Find returns the value associated with a key, or zero if not present.
2525// The found result reports whether the key was found.
2526func (m *Map(K, V)) Find(key K) (V, bool) {
2527 pn := m.find(key)
2528 if *pn == nil {
2529 var zero V // see the discussion of zero values, above
2530 return zero, false
2531 }
2532 return (*pn).val, true
2533}
2534
2535// keyValue is a pair of key and value used when iterating.
2536type keyValue(type K, V) struct {
2537 key K
2538 val V
2539}
2540
2541// InOrder returns an iterator that does an in-order traversal of the map.
2542func (m *Map(K, V)) InOrder() *Iterator(K, V) {
2543 sender, receiver := chans.Ranger(keyValue(K, V))()
2544 var f func(*node(K, V)) bool
2545 f = func(n *node(K, V)) bool {
2546 if n == nil {
2547 return true
2548 }
2549 // Stop sending values if sender.Send returns false,
2550 // meaning that nothing is listening at the receiver end.
2551 return f(n.left) &&
2552 sender.Send(keyValue(K, V){n.key, n.val}) &&
2553 f(n.right)
2554 }
2555 go func() {
2556 f(m.root)
2557 sender.Close()
2558 }()
2559 return &Iterator{receiver}
2560}
2561
2562// Iterator is used to iterate over the map.
2563type Iterator(type K, V) struct {
2564 r *chans.Receiver(keyValue(K, V))
2565}
2566
2567// Next returns the next key and value pair, and a boolean indicating
2568// whether they are valid or whether we have reached the end.
2569func (it *Iterator(K, V)) Next() (K, V, bool) {
2570 keyval, ok := it.r.Next()
2571 if !ok {
2572 var zerok K
2573 var zerov V
2574 return zerok, zerov, false
2575 }
2576 return keyval.key, keyval.val, true
2577}
2578```
2579
2580This is what it looks like to use this package:
2581
2582```Go
2583import "container/orderedmap"
2584
2585var m = orderedmap.New(string, string)(strings.Compare)
2586
2587func Add(a, b string) {
2588 m.Insert(a, b)
2589}
2590```
2591
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002592#### Append
Russ Cox00fd2f62018-08-23 15:11:30 -04002593
2594The predeclared `append` function exists to replace the boilerplate
2595otherwise required to grow a slice.
2596Before `append` was added to the language, there was a function `Add`
2597in the bytes package with the signature
2598
2599```Go
2600func Add(s, t []byte) []byte
2601```
2602
2603that appended two `[]byte` values together, returning a new slice.
2604That was fine for `[]byte`, but if you had a slice of some other
2605type, you had to write essentially the same code to append more
2606values.
2607If this design were available back then, perhaps we would not have
2608added `append` to the language.
2609Instead, we could write something like this:
2610
2611```Go
2612package slices
2613
2614// Append adds values to the end of a slice, returning a new slice.
2615func Append(type T)(s []T, t ...T) []T {
2616 lens := len(s)
2617 tot := lens + len(t)
2618 if tot <= cap(s) {
2619 s = s[:tot]
2620 } else {
2621 news := make([]T, tot, tot + tot/2)
2622 copy(news, s)
2623 s = news
2624 }
2625 copy(s[lens:tot], t)
2626 return s
2627}
2628```
2629
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002630That example uses the predeclared `copy` function, but that's OK, we
Russ Cox00fd2f62018-08-23 15:11:30 -04002631can write that one too:
2632
2633```Go
2634// Copy copies values from t to s, stopping when either slice is
2635// full, returning the number of values copied.
2636func Copy(type T)(s, t []T) int {
2637 i := 0
2638 for ; i < len(s) && i < len(t); i++ {
2639 s[i] = t[i]
2640 }
2641 return i
2642}
2643```
2644
2645These functions can be used as one would expect:
2646
2647```Go
2648 s := slices.Append([]int{1, 2, 3}, 4, 5, 6)
2649 slices.Copy(s[3:], []int{7, 8, 9})
2650```
2651
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002652This code doesn't implement the special case of appending or copying a
2653`string` to a `[]byte`, and it's unlikely to be as efficient as the
Russ Cox00fd2f62018-08-23 15:11:30 -04002654implementation of the predeclared function.
2655Still, this example shows that using this design would permit append
2656and copy to be written generically, once, without requiring any
2657additional special language features.
2658
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002659#### Metrics
Russ Cox00fd2f62018-08-23 15:11:30 -04002660
2661In a [Go experience
2662report](https://medium.com/@sameer_74231/go-experience-report-for-generics-google-metrics-api-b019d597aaa4)
2663Sameer Ajmani describes a metrics implementation.
2664Each metric has a value and one or more fields.
2665The fields have different types.
2666Defining a metric requires specifying the types of the fields, and
2667creating a value with an Add method.
2668The Add method takes the field types as arguments, and records an
2669instance of that set of fields.
2670The C++ implementation uses a variadic template.
2671The Java implementation includes the number of fields in the name of
2672the type.
2673Both the C++ and Java implementations provide compile-time type-safe
2674Add methods.
2675
2676Here is how to use this design to provide similar functionality in
2677Go with a compile-time type-safe Add method.
2678Because there is no support for a variadic number of type arguments,
2679we must use different names for a different number of arguments, as in
2680Java.
2681This implementation only works for comparable types.
2682A more complex implementation could accept a comparison function to
2683work with arbitrary types.
2684
2685```Go
2686package metrics
2687
2688import "sync"
2689
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002690type Metric1(type T comparable) struct {
Russ Cox00fd2f62018-08-23 15:11:30 -04002691 mu sync.Mutex
2692 m map[T]int
2693}
2694
2695func (m *Metric1(T)) Add(v T) {
2696 m.mu.Lock()
2697 defer m.mu.Unlock()
2698 if m.m == nil {
2699 m.m = make(map[T]int)
2700 }
2701 m[v]++
2702}
2703
2704contract cmp2(T1, T2) {
2705 comparable(T1)
2706 comparable(T2)
2707}
2708
2709type key2(type T1, T2 cmp2) struct {
2710 f1 T1
2711 f2 T2
2712}
2713
2714type Metric2(type T1, T2 cmp2) struct {
2715 mu sync.Mutex
2716 m map[key2(T1, T2)]int
2717}
2718
2719func (m *Metric2(T1, T2)) Add(v1 T1, v2 T2) {
2720 m.mu.Lock()
2721 defer m.mu.Unlock()
2722 if m.m == nil {
2723 m.m = make(map[key2(T1, T2)]int)
2724 }
2725 m[key(T1, T2){v1, v2}]++
2726}
2727
2728contract cmp3(T1, T2, T3) {
2729 comparable(T1)
2730 comparable(T2)
2731 comparable(T3)
2732}
2733
2734type key3(type T1, T2, T3 cmp3) struct {
2735 f1 T1
2736 f2 T2
2737 f3 T3
2738}
2739
2740type Metric3(type T1, T2, T3 cmp3) struct {
2741 mu sync.Mutex
2742 m map[key3(T1, T2, T3)]int
2743}
2744
2745func (m *Metric3(T1, T2, T3)) Add(v1 T1, v2 T2, v3 T3) {
2746 m.mu.Lock()
2747 defer m.mu.Unlock()
2748 if m.m == nil {
2749 m.m = make(map[key3]int)
2750 }
2751 m[key(T1, T2, T3){v1, v2, v3}]++
2752}
2753
2754// Repeat for the maximum number of permitted arguments.
2755```
2756
2757Using this package looks like this:
2758
2759```Go
2760import "metrics"
2761
2762var m = metrics.Metric2(string, int){}
2763
2764func F(s string, i int) {
2765 m.Add(s, i) // this call is type checked at compile time
2766}
2767```
2768
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002769This package implementation has a certain amount of repetition due to
2770the lack of support for variadic package type parameters.
Russ Cox00fd2f62018-08-23 15:11:30 -04002771Using the package, though, is easy and type safe.
2772
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002773#### List transform
Russ Cox00fd2f62018-08-23 15:11:30 -04002774
2775While slices are efficient and easy to use, there are occasional cases
2776where a linked list is appropriate.
2777This example primarily shows transforming a linked list of one type to
2778another type, as an example of using different instantiations of the
2779same parameterized type.
2780
2781```Go
2782package list
2783
2784// List is a linked list.
2785type List(type T) struct {
2786 head, tail *element(T)
2787}
2788
2789// An element is an entry in a linked list.
2790type element(type T) struct {
2791 next *element(T)
2792 val T
2793}
2794
2795// Push pushes an element to the end of the list.
2796func (lst *List(T)) Push(v T) {
2797 if lst.tail == nil {
2798 lst.head = &element(T){val: v}
2799 lst.tail = lst.head
2800 } else {
2801 lst.tail.next = &element(T){val: v }
2802 lst.tail = lst.tail.next
2803 }
2804}
2805
2806// Iterator ranges over a list.
2807type Iterator(type T) struct {
2808 next **element(T)
2809}
2810
2811// Range returns an Iterator starting at the head of the list.
2812func (lst *List(T)) Range() *Iterator(T) {
2813 return Iterator(T){next: &lst.head}
2814}
2815
2816// Next advances the iterator.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002817// It returns whether there are more elements.
Russ Cox00fd2f62018-08-23 15:11:30 -04002818func (it *Iterator(T)) Next() bool {
2819 if *it.next == nil {
2820 return false
2821 }
2822 it.next = &(*it.next).next
2823 return true
2824}
2825
2826// Val returns the value of the current element.
2827// The bool result reports whether the value is valid.
2828func (it *Iterator(T)) Val() (T, bool) {
2829 if *it.next == nil {
2830 var zero T
2831 return zero, false
2832 }
2833 return (*it.next).val, true
2834}
2835
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002836// Transform runs a transform function on a list returning a new list.
Russ Cox00fd2f62018-08-23 15:11:30 -04002837func Transform(type T1, T2)(lst *List(T1), f func(T1) T2) *List(T2) {
2838 ret := &List(T2){}
2839 it := lst.Range()
2840 for {
2841 if v, ok := it.Val(); ok {
2842 ret.Push(f(v))
2843 }
2844 it.Next()
2845 }
2846 return ret
2847}
2848```
2849
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002850#### Context
Russ Cox00fd2f62018-08-23 15:11:30 -04002851
2852The standard "context" package provides a `Context.Value` method to
2853fetch a value from a context.
2854The method returns `interface{}`, so using it normally requires a type
2855assertion to the correct type.
2856Here is an example of how we can add type parameters to the "context"
2857package to provide a type-safe wrapper around `Context.Value`.
2858
2859```Go
2860// Key is a key that can be used with Context.Value.
2861// Rather than calling Context.Value directly, use Key.Load.
2862//
2863// The zero value of Key is not ready for use; use NewKey.
2864type Key(type V) struct {
2865 name string
2866}
2867
2868// NewKey returns a key used to store values of type V in a Context.
2869// Every Key returned is unique, even if the name is reused.
2870func NewKey(type V)(name string) *Key {
2871 return &Key(V){name: name}
2872}
2873
2874// WithValue returns a new context with v associated with k.
2875func (k *Key(V)) WithValue(parent Context, v V) Context {
2876 return WithValue(parent, k, v)
2877}
2878
2879// Value loads the value associated with k from ctx and reports
2880//whether it was successful.
2881func (k *Key(V)) Value(ctx Context) (V, bool) {
2882 v, present := ctx.Value(k).(V)
2883 return v.(V), present
2884}
2885
2886// String returns the name and expected value type.
2887func (k *Key(V)) String() string {
2888 var v V
2889 return fmt.Sprintf("%s(%T)", k.name, v)
2890}
2891```
2892
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002893To see how this might be used, consider the net/http package's
Russ Cox00fd2f62018-08-23 15:11:30 -04002894`ServerContextKey`:
2895
2896```Go
2897var ServerContextKey = &contextKey{"http-server"}
2898
2899 // used as:
2900 ctx := context.Value(ServerContextKey, srv)
2901 s, present := ctx.Value(ServerContextKey).(*Server)
2902```
2903
2904This could be written instead as
2905
2906```Go
2907var ServerContextKey = context.NewKey(*Server)("http_server")
2908
2909 // used as:
2910 ctx := ServerContextKey.WithValue(ctx, srv)
2911 s, present := ServerContextKey.Value(ctx)
2912```
2913
2914Code that uses `Key.WithValue` and `Key.Value` instead of
2915`context.WithValue` and `context.Value` does not need any type
2916assertions and is compile-time type-safe.
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002917
2918#### Dot product
2919
2920A generic dot product implementation that works for slices of any
2921numeric type.
2922
2923```Go
2924// Numeric is a contract that matches any numeric type.
2925// It would likely be in a contracts package in the standard library.
2926contract Numeric(T) {
2927 T int, int8, int16, int32, int64,
2928 uint, uint8, uint16, uint32, uint64, uintptr,
2929 float32, float64,
2930 complex64, complex128
2931}
2932
2933func DotProduct(type T Numeric)(s1, s2 []T) T {
2934 if len(s1) != len(s2) {
2935 panic("DotProduct: slices of unequal length")
2936 }
2937 var r T
2938 for i := range s1 {
2939 r += s1[i] * s2[i]
2940 }
2941 return r
2942}
2943```
2944
2945#### Absolute difference
2946
2947Compute the absolute difference between two numeric values, by using
2948an `Abs` method.
2949This uses the same `Numeric` contract defined in the last example.
2950
2951This example uses more machinery than is appropriate for the simple
2952case of computing the absolute difference.
2953It is intended to show how the common part of algorithms can be
2954factored into code that uses methods, where the exact definition of
2955the methods can very based on the kind of type being used.
2956
2957```Go
2958// NumericAbs matches numeric types with an Abs method.
2959contract NumericAbs(T) {
2960 Numeric(T)
2961 T Abs() T
2962}
2963
2964// AbsDifference computes the absolute value of the difference of
2965// a and b, where the absolute value is determined by the Abs method.
2966func AbsDifference(type T NumericAbs)(a, b T) T {
2967 d := a - b
2968 return d.Abs()
2969}
2970```
2971
2972We can define an `Abs` method appropriate for different numeric types.
2973
2974```Go
2975// OrderedNumeric matches numeric types that support the < operator.
2976contract OrderedNumeric(T) {
2977 T int, int8, int16, int32, int64,
2978 uint, uint8, uint16, uint32, uint64, uintptr,
2979 float32, float64
2980}
2981
2982// Complex matches the two complex types, which do not have a < operator.
2983contract Complex(T) {
2984 T complex64, complex128
2985}
2986
2987// OrderedAbs is a helper type that defines an Abs method for
2988// ordered numeric types.
2989type OrderedAbs(type T OrderedNumeric) T
2990
Robert Griesemer8a1c5492019-12-19 13:56:06 -08002991func (a OrderedAbs(T)) Abs() OrderedAbs(T) {
Ian Lance Taylor4a54a002019-07-26 23:21:48 -07002992 if a < 0 {
2993 return -a
2994 }
2995 return a
2996}
2997
2998// ComplexAbs is a helper type that defines an Abs method for
2999// complex types.
3000type ComplexAbs(type T Complex) T
3001
3002func (a ComplexAbs(T)) Abs() T {
3003 r := float64(real(a))
3004 i := float64(imag(a))
3005 d := math.Sqrt(r * r + i * i)
3006 return T(complex(d, 0))
3007}
3008```
3009
3010We can then define functions that do the work for the caller by
3011converting to and from the types we just defined.
3012
3013```Go
3014func OrderedAbsDifference(type T OrderedNumeric)(a, b T) T {
3015 return T(AbsDifference(OrderedAbs(T)(a), OrderedAbs(T)(b)))
3016}
3017
3018func ComplexAbsDifference(type T Complex)(a, b T) T {
3019 return T(AbsDifference(ComplexAbs(T)(a), ComplexAbs(T)(b)))
3020}
3021```
3022
3023It's worth noting that this design is not powerful enough to write
3024code like the following:
3025
3026```Go
3027// This function is INVALID.
3028func GeneralAbsDifference(type T Numeric)(a, b T) T {
3029 switch a.(type) {
3030 case int, int8, int16, int32, int64,
3031 uint, uint8, uint16, uint32, uint64, uintptr,
3032 float32, float64:
3033 return OrderedAbsDifference(a, b) // INVALID
3034 case complex64, complex128:
3035 return ComplexAbsDifference(a, b) // INVALID
3036 }
3037}
3038```
3039
3040The calls to `OrderedAbsDifference` and `ComplexAbsDifference` are
3041invalid, because not all the types that satisfy the `Numeric` contract
3042can satisfy the `OrderedNumeric` or `Complex` contracts.
3043Although the type switch means that this code would conceptually work
3044at run time, there is no support for writing this code at compile
3045time.
3046This another of way of expressing one of the omissions listed above:
3047this design does not provide for specialization.