1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // This file shows some examples of generic types.
6
7 package p
8
9 // List is just what it says - a slice of E elements.
10 type List[E any] []E
11
12 // A generic (parameterized) type must always be instantiated
13 // before it can be used to designate the type of a variable
14 // (including a struct field, or function parameter); though
15 // for the latter cases, the provided type may be another type
16 // parameter. So:
17 var _ List[byte] = []byte{}
18
19 // A generic binary tree might be declared as follows.
20 type Tree[E any] struct {
21 left, right *Tree[E]
22 payload E
23 }
24
25 // A simple instantiation of Tree:
26 var root1 Tree[int]
27
28 // The actual type parameter provided may be a generic type itself:
29 var root2 Tree[List[int]]
30
31 // A couple of more complex examples.
32 // We don't need extra parentheses around the element type of the slices on
33 // the right (unlike when we use ()'s rather than []'s for type parameters).
34 var _ List[List[int]] = []List[int]{}
35 var _ List[List[List[Tree[int]]]] = []List[List[Tree[int]]]{}
36
37 // Type parameters act like type aliases when used in generic types
38 // in the sense that we can "emulate" a specific type instantiation
39 // with type aliases.
40 type T1[P any] struct {
41 f P
42 }
43
44 type T2[P any] struct {
45 f struct {
46 g P
47 }
48 }
49
50 var x1 T1[struct{ g int }]
51 var x2 T2[int]
52
53 func _() {
54 // This assignment is invalid because the types of x1, x2 are T1(...)
55 // and T2(...) respectively, which are two different defined types.
56 x1 = x2 // ERROR assignment
57
58 // This assignment is valid because the types of x1.f and x2.f are
59 // both struct { g int }; the type parameters act like type aliases
60 // and their actual names don't come into play here.
61 x1.f = x2.f
62 }
63
64 // We can verify this behavior using type aliases instead:
65 type T1a struct {
66 f A1
67 }
68 type A1 = struct { g int }
69
70 type T2a struct {
71 f struct {
72 g A2
73 }
74 }
75 type A2 = int
76
77 var x1a T1a
78 var x2a T2a
79
80 func _() {
81 x1a = x2a // ERROR assignment
82 x1a.f = x2a.f
83 }
84
85 // Another interesting corner case are generic types that don't use
86 // their type arguments. For instance:
87 type T[P any] struct{}
88
89 var xint T[int]
90 var xbool T[bool]
91
92 // Are these two variables of the same type? After all, their underlying
93 // types are identical. We consider them to be different because each type
94 // instantiation creates a new named type, in this case T<int> and T<bool>
95 // even if their underlying types are identical. This is sensible because
96 // we might still have methods that have different signatures or behave
97 // differently depending on the type arguments, and thus we can't possibly
98 // consider such types identical. Consequently:
99 func _() {
100 xint = xbool // ERROR assignment
101 }
102
103 // Generic types cannot be used without instantiation.
104 var _ T // ERROR cannot use generic type T
105
106 // In type context, generic (parameterized) types cannot be parenthesized before
107 // being instantiated. See also NOTES entry from 12/4/2019.
108 var _ (T /* ERROR cannot use generic type T */ )[ /* ERROR expected ';' */ int]
109
110 // All types may be parameterized, including interfaces.
111 type I1[T any] interface{
112 m1(T)
113 }
114
115 // There is no such thing as a variadic generic type.
116 type _[T ... /* ERROR invalid use of ... */ interface{}] struct{}
117
118 // Generic interfaces may be embedded as one would expect.
119 type I2 interface {
120 I1(int) // method!
121 I1[string] // embedded I1
122 }
123
124 func _() {
125 var x I2
126 x.I1(0)
127 x.m1("foo")
128 }
129
130 type I0 interface {
131 m0()
132 }
133
134 type I3 interface {
135 I0
136 I1[bool]
137 m(string)
138 }
139
140 func _() {
141 var x I3
142 x.m0()
143 x.m1(true)
144 x.m("foo")
145 }
146
147 // We accept parenthesized embedded struct fields so we can distinguish between
148 // a named field with a parenthesized type foo (T) and an embedded parameterized
149 // type (foo(T)), similarly to interface embedding.
150 // They still need to be valid embedded types after the parentheses are stripped
151 // (i.e., in contrast to interfaces, we cannot embed a struct literal). The name
152 // of the embedded field is derived as before, after stripping parentheses.
153 // (7/14/2020: See comment above. We probably will revert this generalized ability
154 // if we go with [] for type parameters.)
155 type _ struct {
156 int8
157 *int16
158 *List[int]
159
160 int8 /* ERROR int8 redeclared */
161 * /* ERROR List redeclared */ List[int]
162 }
163
164 // It's possible to declare local types whose underlying types
165 // are type parameters. As with ordinary type definitions, the
166 // types underlying properties are "inherited" but the methods
167 // are not.
168 func _[T interface{ m(); type int }]() {
169 type L T
170 var x L
171
172 // m is not defined on L (it is not "inherited" from
173 // its underlying type).
174 x.m /* ERROR x.m undefined */ ()
175
176 // But the properties of T, such that as that it supports
177 // the operations of the types given by its type bound,
178 // are also the properties of L.
179 x++
180 _ = x - x
181
182 // On the other hand, if we define a local alias for T,
183 // that alias stands for T as expected.
184 type A = T
185 var y A
186 y.m()
187 _ = y < 0
188 }
189
190 // As a special case, an explicit type argument may be omitted
191 // from a type parameter bound if the type bound expects exactly
192 // one type argument. In that case, the type argument is the
193 // respective type parameter to which the type bound applies.
194 // Note: We may not permit this syntactic sugar at first.
195 // Note: This is now disabled. All examples below are adjusted.
196 type Adder[T any] interface {
197 Add(T) T
198 }
199
200 // We don't need to explicitly instantiate the Adder bound
201 // if we have exactly one type parameter.
202 func Sum[T Adder[T]](list []T) T {
203 var sum T
204 for _, x := range list {
205 sum = sum.Add(x)
206 }
207 return sum
208 }
209
210 // Valid and invalid variations.
211 type B0 interface {}
212 type B1[_ any] interface{}
213 type B2[_, _ any] interface{}
214
215 func _[T1 B0]()
216 func _[T1 B1[T1]]()
217 func _[T1 B2 /* ERROR cannot use generic type .* without instantiation */ ]()
218
219 func _[T1, T2 B0]()
220 func _[T1 B1[T1], T2 B1[T2]]()
221 func _[T1, T2 B2 /* ERROR cannot use generic type .* without instantiation */ ]()
222
223 func _[T1 B0, T2 B1[T2]]() // here B1 applies to T2
224
225 // When the type argument is left away, the type bound is
226 // instantiated for each type parameter with that type
227 // parameter.
228 // Note: We may not permit this syntactic sugar at first.
229 func _[A Adder[A], B Adder[B], C Adder[A]]() {
230 var a A // A's type bound is Adder[A]
231 a = a.Add(a)
232 var b B // B's type bound is Adder[B]
233 b = b.Add(b)
234 var c C // C's type bound is Adder[A]
235 a = c.Add(a)
236 }
237
238 // The type of variables (incl. parameters and return values) cannot
239 // be an interface with type constraints or be/embed comparable.
240 type I interface {
241 type int
242 }
243
244 var (
245 _ interface /* ERROR contains type constraints */ {type int}
246 _ I /* ERROR contains type constraints */
247 )
248
249 func _(I /* ERROR contains type constraints */ )
250 func _(x, y, z I /* ERROR contains type constraints */ )
251 func _() I /* ERROR contains type constraints */
252
253 func _() {
254 var _ I /* ERROR contains type constraints */
255 }
256
257 type C interface {
258 comparable
259 }
260
261 var _ comparable /* ERROR comparable */
262 var _ C /* ERROR comparable */
263
264 func _(_ comparable /* ERROR comparable */ , _ C /* ERROR comparable */ )
265
266 func _() {
267 var _ comparable /* ERROR comparable */
268 var _ C /* ERROR comparable */
269 }
270
271 // Type parameters are never const types, i.e., it's
272 // not possible to declare a constant of type parameter type.
273 // (If a type list contains just a single const type, we could
274 // allow it, but such type lists don't make much sense in the
275 // first place.)
276 func _[T interface { type int, float64 }]() {
277 // not valid
278 const _ = T /* ERROR not constant */ (0)
279 const _ T /* ERROR invalid constant type T */ = 1
280
281 // valid
282 var _ = T(0)
283 var _ T = 1
284 _ = T(0)
285 }
286
287
View as plain text