Skip to content

Commit b571c32

Browse files
ianlancetayloradg
authored andcommitted
design: add "Go should have generics" proposal
This change proposes the notion of generics in Go, and includes four proposals from years' past that are each flawed in their own ways. These historical documents are included to show what a complete generics proposal looks like. Updates golang/go#15292 Change-Id: Ice1c35af618a043d55ceec54f182d45a4de780e1 Reviewed-on: https://go-review.googlesource.com/22057 Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent eac21d3 commit b571c32

File tree

5 files changed

+4415
-0
lines changed

5 files changed

+4415
-0
lines changed

design/15292-generics.md

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
# Proposal: Go should have generics
2+
3+
Author: [Ian Lance Taylor]([email protected])
4+
5+
Created: January 2011
6+
7+
Last updated: April 2016
8+
9+
Discussion at https://golang.org/issue/15292
10+
11+
## Abstract
12+
13+
Go should support some form of generic programming.
14+
Generic programming enables the representation of algorithms and data
15+
structures in a generic form, with concrete elements of the code
16+
(such as types) factored out.
17+
It means the ability to express algorithms with minimal assumptions
18+
about data structures, and vice-versa
19+
(paraphrasing [Jazayeri, et al](http://www.dagstuhl.de/en/program/calendar/semhp/?semnr=98171)).
20+
21+
## Background
22+
23+
### Generic arguments in favor of generics
24+
25+
People can write code once, saving coding time.
26+
People can fix a bug in one instance without having to remember to fix it
27+
in others.
28+
Generics avoid boilerplate: less coding by copying and editing.
29+
30+
Generics save time testing code: they increase the amount of code
31+
that can be type checked at compile time rather than at run time.
32+
33+
Every statically typed language in current use has generics in one
34+
form or another (even C has generics, where they are called preprocessor macros;
35+
[example](https://gcc.gnu.org/viewcvs/gcc/trunk/gcc/vec.h?revision=165314&view=markup&pathrev=165314)).
36+
37+
### Existing support for generic programming in Go
38+
39+
Go already supports a form of generic programming via interfaces.
40+
People can write an abstract algorithm that works with any type that
41+
implements the interface.
42+
However, interfaces are limited because the methods must use specific types.
43+
There is no way to write an interface with a method that takes an
44+
argument of type T, for any T, and returns a value of the same type.
45+
There is no way to write an interface with a method that compares two
46+
values of the same type T, for any T.
47+
The assumptions that interfaces require about the types that satisfy
48+
them are not minimal.
49+
50+
Interfaces are not simply types; they are also values.
51+
There is no way to use interface types without using interface values,
52+
and interface values aren’t always efficient.
53+
There is no way to create a slice of the dynamic type of an interface.
54+
That is, there is no way to avoid boxing.
55+
56+
### Specific arguments in favor of generics in Go
57+
58+
Generics permit type-safe polymorphic containers.
59+
Go currently has a very limited set of such containers: slices, and
60+
maps of most but not all types.
61+
Not every program can be written using a slice or map.
62+
63+
Look at the functions `SortInts`, `SortFloats`, `SortStrings` in the
64+
sort package.
65+
Or `SearchInts`, `SearchFloats`, `SearchStrings`.
66+
Or the `Len`, `Less`, and `Swap` methods of `byName` in package io/ioutil.
67+
Pure boilerplate copying.
68+
69+
The `copy` and `append` functions exist because they make slices much
70+
more useful.
71+
Generics would mean that these functions are unnecessary.
72+
Generics would make it possible to write similar functions for maps
73+
and channels, not to mention user created data types.
74+
Granted, slices are the most important composite data type, and that’s why
75+
these functions were needed, but other data types are still useful.
76+
77+
It would be nice to be able to make a copy of a map.
78+
Right now that function can only be written for a specific map type,
79+
but, except for types, the same code works for any map type.
80+
Similarly, it would be nice to be able to multiplex one channel onto
81+
two, without having to rewrite the function for each channel type.
82+
One can imagine a range of simple channel manipulators, but they can
83+
not be written because the type of the channel must be specified
84+
explicitly.
85+
86+
Generics let people express the relationship between function parameters
87+
and results.
88+
Consider the simple Transform function that calls a function on every
89+
element of a slice, returning a new slice.
90+
We want to write something like
91+
```
92+
func Transform(s []T, f func(T) U) []U
93+
```
94+
but this can not be expressed in current Go.
95+
96+
In many Go programs, people only have to write explicit types in function
97+
signatures.
98+
Without generics, they also have to write them in another place: in the
99+
type assertion needed to convert from an interface type back to the
100+
real type.
101+
The lack of static type checking provided by generics makes the code
102+
heavier.
103+
104+
### What we want from generics in Go
105+
106+
Any implementation of generics in Go should support the following.
107+
108+
* Define generic types based on types that are not known until they are instantiated.
109+
* Write algorithms to operate on values of these types.
110+
* Name generic types and name specific instantiations of generic types.
111+
* Use types derived from generic types, as in making a slice of a generic type,
112+
or conversely, given a generic type known to be a slice, defining a variable
113+
with the slice’s element type.
114+
* Restrict the set of types that may be used to instantiate a generic type, to
115+
ensure that the generic type is only instantiated with types that support the
116+
* required operations.
117+
* Do not require an explicit relationship between the definition of a generic
118+
type or function and its use. That is, programs should not have to
119+
explicitly say *type T implements generic G*.
120+
* Write interfaces that describe explicit relationships between generic types,
121+
as in a method that takes two parameters that must both be the same unknown type.
122+
* Do not require explicit instantiation of generic types or functions; they
123+
should be instantiated as needed.
124+
125+
### The downsides of generics
126+
127+
Generics affect the whole language.
128+
It is necessary to evaluate every single language construct to see how
129+
it will work with generics.
130+
131+
Generics affect the whole standard library.
132+
It is desirable to have the standard library make effective use of generics.
133+
Every existing package should be reconsidered to see whether it would benefit
134+
from using generics.
135+
136+
It becomes tempting to build generics into the standard library at a
137+
very low level, as in C++ `std::basic_string<char, std::char_traits<char>, std::allocator<char> >`.
138+
This has its benefits&mdash;otherwise nobody would do it&mdash;but it has
139+
wide-ranging and sometimes surprising effects, as in incomprehensible
140+
C++ error messages.
141+
142+
As [Russ pointed out](http://research.swtch.com/generic), generics are
143+
a trade off between programmer time, compilation time, and execution
144+
time.
145+
146+
Go is currently optimizing compilation time and execution time at the
147+
expense of programmer time.
148+
Compilation time is a significant benefit of Go.
149+
Can we retain compilation time benefits without sacrificing too much
150+
execution time?
151+
152+
Unless we choose to optimize execution time, operations that appear
153+
cheap may be more expensive if they use values of generic type.
154+
This may be subtly confusing for programmers.
155+
I think this is less important for Go than for some other languages,
156+
as some operations in Go already have hidden costs such as array
157+
bounds checks.
158+
Still, it would be essential to ensure that the extra cost of using
159+
values of generic type is tightly bounded.
160+
161+
Go has a lightweight type system.
162+
Adding generic types inevitably makes the type system more complex.
163+
It is essential that the result remain lightweight.
164+
165+
The upsides of the downsides are that Go is a relatively small
166+
language, and it really is possible to consider every aspect of the
167+
language when adding generics.
168+
At least the following sections of the spec would need to be extended:
169+
Types, Type Identity, Assignability, Type assertions, Calls, Type
170+
switches, For statements with range clauses.
171+
172+
Only a relatively small number of packages will need to be
173+
reconsidered in light of generics: container/*, sort, flag, perhaps
174+
bytes.
175+
Packages that currently work in terms of interfaces will generally be
176+
able to continue doing so.
177+
178+
### Conclusion
179+
180+
Generics will make the language safer, more efficient to use, and more
181+
powerful.
182+
These advantages are harder to quantify than the disadvantages, but
183+
they are real.
184+
185+
## Examples of potential uses of generics in Go
186+
187+
* Containers
188+
* User-written hash tables that are compile-time type-safe, rather than
189+
converting slice keys to string and using maps
190+
* Sorted maps (red-black tree or similar)
191+
* Double-ended queues, circular buffers
192+
* A simpler Heap
193+
* `Keys(map[K]V) []K`, `Values(map[K]V) []V`
194+
* Caches
195+
* Compile-time type-safe `sync.Pool`
196+
* Generic algorithms that work with these containers in a type-safe way.
197+
* Union/Intersection
198+
* Sort, StableSort, Find
199+
* Copy (a generic container, and also copy a map)
200+
* Transform a container by applying a function--LISP `mapcar` and friends
201+
* math and math/cmplx
202+
* testing/quick.{`Check`,`CheckEqual`}
203+
* Mixins
204+
* like `ioutil.NopCloser`, but preserving other methods instead of
205+
restricting to the passed-in interface (see the `ReadFoo` variants of
206+
`bytes.Buffer`)
207+
* protobuf `proto.Clone`
208+
* Eliminate boilerplate when calling sort function
209+
* Generic diff: `func [T] Diff(x, y []T) []range`
210+
* Channel operations
211+
* Merge N channels onto one
212+
* Multiplex one channel onto N
213+
* The [worker-pool pattern](http://play.golang.org/p/b5XRHnxzZF)
214+
* Graph algorithms, for example immediate dominator computation
215+
* Multi-dimensional arrays (not slices) of different lengths
216+
* Many of the packages in go.text could benefit from it to avoid duplicate
217+
implementation or APIs for `string` and `[]byte` variants; many points that
218+
could benefit need high performance, though, and generics should provide that
219+
benefit
220+
221+
## Proposal
222+
223+
I won’t discuss a specific implementation proposal here: my hope is
224+
that this document helps show people that generics are worth having
225+
provided the downsides can be kept under control.
226+
227+
The following documents are my previous generics proposals,
228+
presented for historic reference. All are flawed in various ways.
229+
230+
* [Type functions](NNNN/2010-06-type-functions.md) (June 2010)
231+
* [Generalized types](NNNN/2011-03-gen.md) (March 2011)
232+
* [Generalized types](NNNN/2013-10-gen.md) (October 2013)
233+
* [Type parameters](NNNN/2013-12-type-params.md) (December 2013)

0 commit comments

Comments
 (0)