Ian Lance Taylor | b571c32 | 2016-03-31 09:36:41 +1100 | [diff] [blame] | 1 | # Proposal: Go should have generics |
| 2 | |
| 3 | Author: [Ian Lance Taylor](iant@golang.org) |
| 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 |
Suriyaa Sundararuban | 2c6bc83 | 2018-06-12 12:48:52 +0000 | [diff] [blame] | 19 | (paraphrasing [Jazayeri, et al](https://www.dagstuhl.de/en/program/calendar/semhp/?semnr=98171)). |
Ian Lance Taylor | b571c32 | 2016-03-31 09:36:41 +1100 | [diff] [blame] | 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 |
Andrew Gerrand | ab418bc | 2016-04-14 13:38:40 +1000 | [diff] [blame] | 116 | required operations. |
Ian Lance Taylor | b571c32 | 2016-03-31 09:36:41 +1100 | [diff] [blame] | 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—otherwise nobody would do it—but it has |
| 139 | wide-ranging and sometimes surprising effects, as in incomprehensible |
| 140 | C++ error messages. |
| 141 | |
Suriyaa Sundararuban | 2c6bc83 | 2018-06-12 12:48:52 +0000 | [diff] [blame] | 142 | As [Russ pointed out](https://research.swtch.com/generic), generics are |
Ian Lance Taylor | b571c32 | 2016-03-31 09:36:41 +1100 | [diff] [blame] | 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 |
Suriyaa Sundararuban | 2c6bc83 | 2018-06-12 12:48:52 +0000 | [diff] [blame] | 213 | * The [worker-pool pattern](https://play.golang.org/p/b5XRHnxzZF) |
Ian Lance Taylor | b571c32 | 2016-03-31 09:36:41 +1100 | [diff] [blame] | 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 | |
Andrew Gerrand | bb8acc2 | 2016-04-14 13:38:40 +1000 | [diff] [blame] | 230 | * [Type functions](15292/2010-06-type-functions.md) (June 2010) |
| 231 | * [Generalized types](15292/2011-03-gen.md) (March 2011) |
| 232 | * [Generalized types](15292/2013-10-gen.md) (October 2013) |
| 233 | * [Type parameters](15292/2013-12-type-params.md) (December 2013) |