@@ -110,7 +110,6 @@ extends Comparable<X>`. This implies that current Dart constructors can
110
110
only allow for a declaration that resembles ` D.ofComparable ` if it uses a
111
111
much less precise typing, and relies on some run-time type checks.
112
112
113
-
114
113
``` dart
115
114
// What we can do in current Dart.
116
115
@@ -157,7 +156,7 @@ The extra constraints can be helpful during inference. For instance,
157
156
` Map.keyToList(xs) ` above would yield a ` Map<int, List<int>> ` . In contrast:
158
157
159
158
``` dart
160
- // What we can do in current Dart doesn't work...
159
+ // What we may try to do in current Dart doesn't work...
161
160
162
161
class Map<K, V> {
163
162
Map();
@@ -166,34 +165,31 @@ class Map<K, V> {
166
165
}
167
166
```
168
167
169
- It is possible to create a ` Map<K, List<K>> ` based on an existing
170
- ` Iterable<K> ` using run-time type information. However, Dart does not in
171
- general support this kind of introspection into the run-time value of type
172
- arguments (and Dart does not (yet) have an 'existential open' operation),
173
- so we'd almost always have to use very general types in a way which is
174
- similar to the example above, which is a very substantial reduction in
175
- typing precision.
176
-
177
- However, that won't work because it is a compile-time error to return the
178
- specified map literal in the declaration of ` Map.keyToList ` . So we'd need
179
- to cast it to ` Map<K, V> ` , and that's going to throw in an invocation like
180
- ` Map<int, String>.keyToList(xs) ` .
181
-
182
- With the generic constructor, the actual type arguments like
183
- ` <int, String> ` will be used as a context type for the constructor
184
- invocation. The generic constructor ` Map.keyToList ` fails to infer actual
185
- type arguments such that the resulting return type is a subtype of
186
- ` Map<int, String> ` , and hence an invocation of the generic constructor like
187
- ` Map<int, String>.keyToList(xs) ` will be a compile-time error.
188
-
189
- It should be noted that the type arguments of the class are inaccessible in
168
+ However, that is a compile-time error because it returns a
169
+ ` Map<Object?, List<Object?>> ` where the return type is ` Map<K, V> ` .
170
+ But we don't know ` K ` or ` V ` , and we can't assume that ` V ` is of the form
171
+ ` List<K> ` or a supertype thereof. We might try to cast the map literal to
172
+ ` Map<K, V> ` , and that might work, but an invocation like
173
+ ` Map<int, String>.keyToList(xs) ` will then throw at run time because the
174
+ map literal isn't going to have the required type no matter which iterable
175
+ we are passing as ` keys ` .
176
+
177
+ With the generic constructor and with an invocation like
178
+ ` Map<int, String>.keyToList(xs) ` , the actual type arguments will be used as
179
+ a context type for the constructor invocation. The generic constructor
180
+ ` Map.keyToList ` fails to infer actual type arguments such that the
181
+ resulting return type is a subtype of ` Map<int, String> ` , and hence the
182
+ invocation is a compile-time error.
183
+
184
+ It should be noted that the type parameters of the class are inaccessible in
190
185
a generic constructor declaration. In that sense, the generic constructor
191
186
declaration is similar to a static member declaration, in that it can
192
187
declare and use its own formal type parameters, but it cannot access the
193
188
type parameters from the enclosing class.
194
189
195
190
The similarity to generic static methods goes further. For example, we
196
- could express ` keyToList ` as a static method in current Dart as follows:
191
+ could express ` keyToList ` as a generic static method in current Dart as
192
+ follows:
197
193
198
194
``` dart
199
195
// Emulating `keyToList` as a static method in current Dart.
@@ -210,9 +206,11 @@ void main() {
210
206
}
211
207
```
212
208
209
+ Works perfectly!
210
+
213
211
This illustrates that the new expressive power is not new for static
214
212
members (and the invocations can look exactly the same as a constructor
215
- invocation in many cases).
213
+ invocation in many cases), it is only new for constructors.
216
214
217
215
However, it is still useful to generalize constructors in this way because
218
216
certain situations require the use of a constructor rather than a static
@@ -233,23 +231,30 @@ The grammar is adjusted as follows:
233
231
| <typeIdentifier> <typeArguments> '.' <identifierOrNew>
234
232
<formalParameterList>
235
233
236
- <factoryConstructorSignature> ::= 'const'? 'factory' <constructorSignature>
234
+ <factoryConstructorSignature> ::=
235
+ 'const'? 'factory' <constructorSignature>
237
236
238
237
<redirectingFactoryConstructorSignature> ::=
239
- 'const'? 'factory' <constructorSignature> '=' <constructorDesignation>
238
+ 'const'? 'factory' <constructorSignature> '='
239
+ <constructorDesignation>
240
240
241
- <constantConstructorSignature> ::= 'const' <constructorSignature>
241
+ <constantConstructorSignature> ::=
242
+ 'const' <constructorSignature>
242
243
```
243
244
245
+ A _ type introducing_ declaration is a class declaration, a mixin
246
+ class declaration, a mixin declaration, an enum declaration, or an
247
+ extension type declaration.
248
+
244
249
A compile-time error occurs if the ` <typeIdentifier> ` in the constructor
245
- signature is not the same as the name of the enclosing class, mixin or enum
250
+ signature is not the same as the name of the enclosing type introducing
246
251
declaration, or the name of the on-declaration of the enclosing extension
247
252
declaration.
248
253
249
254
### Static Analysis
250
255
251
- A generic constructor declaration occurs as a member of a class, mixin,
252
- mixin class, enum, or extension declaration. Its current scope is the body
256
+ A generic constructor declaration occurs as a member of a type introducing
257
+ declaration or an extension declaration. Its current scope is the body
253
258
scope of the enclosing declaration. It introduces a type parameter scope
254
259
whose enclosing scope is the current scope of the generic constructor
255
260
declaration, and each type parameter declaration introduces that type
@@ -258,29 +263,29 @@ for the entire generic constructor declaration. Further scopes inside the
258
263
type parameter scope are created in the same way as for non-generic
259
264
constructors.
260
265
261
- * In particular , a parameter of the form ` this.p ` is in scope in the
266
+ * For example , a parameter of the form ` this.p ` is in scope in the
262
267
initializer list, if any, and other parameters are in scope in the body, as
263
268
usual.*
264
269
265
270
We establish some coherence conditions for generic constructors:
266
271
267
272
A compile-time error occurs if any identifier in a generic constructor
268
273
declaration resolves to a type parameter which is declared by the enclosing
269
- class, mixin, enum, or extension declaration.
274
+ type introducing declaration or extension declaration.
270
275
271
276
* In other words, a generic constructor cannot access the type parameters of
272
- the class directly. In this way they are similar to static members.*
277
+ a class etc. directly. In this way they are similar to static members.*
273
278
274
279
Assume that _ D_ is a generic constructor declaration whose constructor
275
280
signature includes a list of actual type arguments which are applied to the
276
281
` <typeIdentifier> ` .
277
282
278
283
* For example, ` C<X>.name<X extends num>() ` applies ` C ` to ` <X> ` .*
279
284
280
- It is a compile-time error if the enclosing class, mixin, or enum
281
- declaration or the on-declaration of the enclosing extension declaration
282
- does not declare any type parameters, or if it declares a different number
283
- of type parameters than the number of type arguments which are passed.
285
+ It is a compile-time error if the enclosing type introducing declaration,
286
+ or the on-declaration of the enclosing extension declaration, does not
287
+ declare any type parameters, or if it declares a different number of type
288
+ parameters than the number of type arguments which are passed.
284
289
285
290
It is a compile-time error unless these type arguments satisfy the declared
286
291
bounds, assuming that the bounds of the generic constructor declaration
@@ -312,7 +317,12 @@ non-generic class).
312
317
In this case, the super-initializer of the constructor (explicit or
313
318
implicit, and excepting ` Object ` that does not have a super-initializer)
314
319
will invoke the superconstructor with actual type arguments that correspond
315
- to the type ` C<T1 .. Tk> ` of the current constructor invocation.
320
+ to the type ` C<T1 .. Tk> ` of the current constructor invocation.
321
+
322
+ That is, if ` C ` is declared with ` k ` type parameters ` X1 .. Xk ` and
323
+ superclass ` B<U1 .. Us> ` then the ` j ` th actual type argument to the super
324
+ constructor invocation is obtained as ` [T1/X1 .. Tk/Xk]Uj ` , for ` j ` in
325
+ ` 1 .. s ` .
316
326
317
327
Moreover, in the body of _ D_ , the reserved word ` this ` has static type
318
328
` C<T1 .. Tk> ` .
@@ -360,8 +370,8 @@ whose constructor signature applies a list of actual type arguments to the
360
370
where ` k ` is zero, which again implies that ` C ` is a non-generic class).
361
371
362
372
In this case, the denoted redirectee constructor is invoked with the same
363
- actual type arguments. It is a compile-time error if the redirectee is a
364
- generic constructor.
373
+ actual type arguments, that is ` T1 .. Tk ` . It is a compile-time error if
374
+ the redirectee is a generic constructor.
365
375
366
376
* This restriction might also be relaxed in the future, if needed.*
367
377
0 commit comments