2
2
3
3
** Author** : eernst@
4
4
5
+ ** Version** : 0.9 (2018-02-22)
6
+
5
7
** Status** : Under implementation.
6
8
7
- ** This document** is an informal specification of the generalized support
8
- in Dart 1.x for the type ` void ` . Dart 2 will have a very similar kind of
9
- generalized support for ` void ` , without the function type subtype exception
10
- that this feature includes for backward compatibility in Dart 1.x. This
11
- document specifies the feature for Dart 1.x and indicates how Dart 2
12
- differs at relevant points.
9
+ ** This document** is a feature specification of the generalized support
10
+ in Dart 2 for the type ` void ` .
13
11
14
- ** The feature** described here, * generalized void* , allows for using the
15
- type ` void ` as a type annotation and as a type argument.
12
+ ** The feature** described here, * generalized void* , allows for using
13
+ ` void ` as a type annotation and as a type argument.
16
14
17
15
The ** motivation** for allowing the extended usage is that it helps
18
16
developers state the intent that a particular ** value should be
@@ -30,34 +28,34 @@ covariantly. For instance, the class `Future<T>` uses return types
30
28
like ` Future<T> ` and ` Stream<T> ` , and it uses ` T ` as a parameter type of a
31
29
callback in the method ` then ` .
32
30
33
- Note that using the value of an expression of type ` void ` is not
31
+ Note that using the value of an expression of type void is not
34
32
technically dangerous, doing so does not violate any constraints at the
35
- level of the language semantics. By using the type ` void ` , developers
33
+ level of the language semantics. By using the type void, developers
36
34
indicate that the value of the corresponding expression evaluation is
37
35
meaningless. Hence, there is ** no requirement** for the generalized void
38
36
mechanism to be strict and ** sound** . However, it is the intention that the
39
37
mechanism should be sufficiently sound to make the mechanism helpful and
40
38
non-frustrating in practice.
41
39
42
- No constraints are imposed on which values may be given type ` void ` , so in
40
+ No constraints are imposed on which values may be given type void, so in
43
41
that sense ` void ` can be considered to be just another name for the type
44
42
` Object ` , flagged as useless. Note that this is an approximate rule in
45
43
Dart 1.x, it fails to hold for function types; it does hold in Dart 2.
46
44
47
45
The mechanisms helping developers to avoid using the value of an expression
48
- of type ` void ` are divided into ** two phases** . This document specifies the
46
+ of type void are divided into ** two phases** . This document specifies the
49
47
first phase.
50
48
51
49
The ** first phase** uses restrictions which are based on syntactic criteria
52
50
in order to ensure that direct usage of the value of an expression of type
53
- ` void ` is a static warning (in Dart 2: an error) . A few exceptions are
51
+ void is a compile-time error. A few exceptions are
54
52
allowed, e.g., type casts, such that developers can explicitly make the
55
53
choice to use such a value. The general rule is that for every expression
56
- of type ` void ` , its value must be ignored.
54
+ of type void, its value must be ignored.
57
55
58
56
The ** second phase** will deal with casts and preservation of
59
57
voidness. Some casts will cause derived expressions to switch from having
60
- type ` void ` to having some other type, and hence those casts introduce the
58
+ type void to having some other type, and hence those casts introduce the
61
59
possibility that "a void value" will get passed and used. Here is an
62
60
example:
63
61
@@ -88,7 +86,7 @@ typeNotVoid ::= // NEW
88
86
type ::= // ENTIRE RULE MODIFIED
89
87
typeNotVoid | 'void'
90
88
redirectingFactoryConstructorSignature ::=
91
- 'const'? 'factory' identifier ('.' identifier)?
89
+ 'const'? 'factory' identifier ('.' identifier)?
92
90
formalParameterList `=' typeNotVoid ('.' identifier)?
93
91
superclass ::=
94
92
'extends' typeNotVoid
@@ -211,7 +209,7 @@ the type void is treated as being the built-in class `Object`.
211
209
are erased to regular function types during compilation. Hence there is no
212
210
need to specify the the typing relations for generic function types. In
213
211
Dart 2, the subtype relationship for generic function types follows from
214
- the rule that ` void ` is treated as ` Object ` .*
212
+ the rule that the type void is treated as ` Object ` .*
215
213
216
214
Consider a function type _ T_ where the return type is the type void. In
217
215
Dart 1.x, the dynamic more-specific-than relation, ` << ` , and the dynamic
@@ -236,78 +234,108 @@ we were to consistently treat the type void as `Object` at run time (as in
236
234
Dart 2) then this assignment would be permitted (but we would then use
237
235
voidness preservation to detect and avoid this situation at compile time).*
238
236
239
- * The semantics of checked mode checks involving types where the type void
237
+ * The semantics of dynamic checks involving types where the type void
240
238
occurs is determined by the semantics of subtype tests, so we do not
241
239
specify that separately.*
242
240
243
- An instantiation of a generic class ` G ` is malbounded if it contains ` void `
244
- as an actual type argument for a formal type parameter, unless that type
245
- parameter does not have a bound, or it has a bound which is the built-in
246
- class ` Object ` , or ` dynamic ` .
241
+ It is a compile-time error to use ` void ` as the bound of a type variable.
242
+
243
+ An instantiation of a generic class ` G ` is malbounded if it contains the
244
+ type void as an actual type argument for a formal type parameter, unless
245
+ that type parameter does not have a bound, or it has a bound which is the
246
+ built-in class ` Object ` , or ` dynamic ` .
247
247
248
248
* The treatment of malbounded types follows the current specification.*
249
249
250
+
250
251
## Static Analysis
251
252
252
- For the static analysis, the more-specific-than relation, ` << ` , and the
253
- subtype relation, ` <: ` , are determined by the same rules as described above
254
- for the dynamic semantics, for both Dart 1.x and Dart 2.
255
-
256
- * That is, the type void is considered to be equivalent to the built-in
257
- class ` Object ` in Dart 1.x, except when used as a return type, in which
258
- case it is effectively considered to be a proper supertype of ` Object ` . In
259
- Dart 2 subtyping, the type void is consistently considered to be equivalent
260
- to the built-in class ` Object ` . As mentioned, this document does not
261
- specify voidness preservation; however, when voidness preservation checks
262
- are added we get an effect in Dart 2 which is similar to the special
263
- treatment of void as a return type in Dart 1.x: The function type downcast
264
- which will be rejected in Dart 1.x (at run time, with a static warning at
265
- compile time) will become a voidness preservation violation, i.e., a
266
- compile-time error.*
267
-
268
- It is a static warning for an expression to have type void (in Dart 2: a
269
- compile-time error), except for the following situations:
270
-
271
- * In an expressionStatement ` e; ` , e may have type void.
253
+ For the static analysis, the subtype relation, ` <: ` , is determined by the
254
+ same rules as described above for the dynamic semantics.
255
+
256
+ * That is, the type void, for the purposes of subtyping, is considered to be
257
+ equivalent to the built-in class ` Object ` . As mentioned, this document does
258
+ not specify voidness preservation. However, when voidness preservation
259
+ checks are added we will get (among other things) an effect which is
260
+ similar to the special treatment of void as a return type which was used in
261
+ Dart 1.x: In Dart 1.x, an implicit downcast from ` void Function() ` to
262
+ ` Object Function() ` will fail at run time, but with voidness preservation
263
+ it will be a compile-time error.*
264
+
265
+ It is a compile-time error to evaluate an expression of type void, except
266
+ for the following situations:
267
+
268
+ * In an expressionStatement ` e; ` , ` e ` may have type void.
272
269
* In the initialization and increment expressions of a for-loop,
273
270
` for (e1; e2; e3) {..} ` , ` e1 ` and ` e3 ` may have type void.
274
- * In a typeCast ` e as T ` , ` e ` may have type void.
271
+ * In a type cast ` e as T ` , ` e ` may have type void.
275
272
* In a parenthesized expression ` (e) ` , ` e ` may have type void.
273
+ * In a conditional expression ` e ? e1 : e2 ` , ` e1 ` and ` e2 ` may have the
274
+ type void; the static type of the conditional expression is then the
275
+ type void. (* This is true even if one of the branches has a different
276
+ type.* )
277
+ * If _ N1_ and _ N2_ are non-terminals in the Dart grammar, and there is a
278
+ derivation of the form _ N1 --> N2_ , and _ N2_ can have type void, then
279
+ _ N1_ can also have type void for such a derivation. * In this derivation
280
+ no additional tokens are included, it is only the non-terminal which
281
+ changes.*
276
282
* In a return statement ` return e; ` , when the return type of the innermost
277
283
enclosing function is the type void, ` e ` may have type void.
278
-
279
- * Note that the parenthesized expression itself has type void, so it is
280
- again subject to the same constraints. Also note that we may not allow
281
- return statements returning an expression of type void in Dart 2, but
282
- it is allowed here for backward compatibility.*
283
-
284
- * The value yielded by an expression of type void must be discarded (and
285
- hence ignored), except when explicitly subjected to a type cast. This
284
+ * An initializing expression for a variable of type void may have the type
285
+ void.
286
+ * An actual parameter expression corresponding to a formal parameter whose
287
+ statically known type annotation is the type void may have the type void.
288
+ * In an expression of the form ` e1 = e2 ` where ` e1 ` is an
289
+ assignableExpression denoting a variable or parameter of type void, ` e2 ` may
290
+ have the type void.
291
+ * Assume that ` e ` is an expression ending in a ` cascadeSection ` of the
292
+ form ` '..' S s = e1 ` where ` S ` is of the form `(cascadeSelector
293
+ argumentPart* ) (assignableSelector argumentPart* )* ` and ` e1` is an
294
+ ` expressionWithoutCascade ` . If ` s ` is an ` assignableSelector ` of the
295
+ form ` '.' identifier ` or ` '?.' identifier ` where the static type of the
296
+ ` identifier ` is the type void, ` e1 ` may have type void; otherwise, if
297
+ ` s ` is an ` assignableSelector ` of the form ` '[' e0 ']' ` where the
298
+ static type of the first formal parameter in the statically known
299
+ declaration of operator ` []= ` is the type void, ` e0 ` may have type
300
+ void; also, if the static type of the second formal parameter is the
301
+ type void, ` e1 ` may have type void.
302
+
303
+ * The rule about non-terminals is needed in order to allow, say, `void x = b
304
+ ? (y) : e2;` where ` y` has type void: ` y` is an identifier which is derived
305
+ from primary, which is derived from postfixExpression, from
306
+ unaryExpression, from multiplicativeExpression, etc. Only if we allow such
307
+ a (trivial) multiplicativeExpression can we allow the corresponding
308
+ (trivial) unaryExpression, etc., all the way down to identifier, and all
309
+ the way up to expression, which is needed for the initialization of ` x ` .*
310
+
311
+ * The general rule is that the value yielded by an expression of type void
312
+ must be discarded (and hence ignored), except when explicitly subjected to
313
+ a type cast, or when returned or assigned to a target of type void. This
286
314
"makes it hard to use a meaningless value", but leaves a small escape hatch
287
315
open for the cases where the developer knows that the typing misrepresents
288
316
the actual situation.*
289
317
290
- It is a static warning (in Dart 2: a compile-time error) if a return
291
- statement ` return e; ` occurs such that the innermost enclosing function
292
- has return type ` void ` and the static type of ` e ` is not the type void.
318
+ It is a compile-time error if a return statement ` return e; ` occurs such
319
+ that the innermost enclosing function has return type ` void ` and the static
320
+ type of ` e ` is not the type void.
293
321
294
- It is a static warning (in Dart 2: a compile-time error) if a function
295
- marked ` async* ` , or ` sync* ` has return type ` void ` .
322
+ It is a compile-time error if a function marked ` async* ` , or ` sync* ` has
323
+ return type ` void ` .
296
324
297
325
* Note that it is allowed for an ` async ` function to have return type
298
326
` void ` . This serves to indicate that said function performs a
299
327
"fire-and-forget" operation, that is, it is not even useful for the caller
300
328
to synchronize with the completion of that task.*
301
329
302
- It is a static warning (Dart 2: a compile-time error) for a for-in
303
- statement to have an iterator expression of type ` T ` such that
304
- ` Iterator<void> ` is the most specific instantiation of ` Iterator ` that is a
305
- superinterface of ` T ` , unless the iteration variable has type void.
330
+ It is a compile-time error for a for-in statement to have an iterator
331
+ expression of type ` T ` such that ` Iterator<void> ` is the most specific
332
+ instantiation of ` Iterator ` that is a superinterface of ` T ` , unless the
333
+ iteration variable has type void.
306
334
307
- It is a static warning (Dart 2: a compile-time error) for an asynchronous
308
- for-in statement to have a stream expression of type ` T ` such that
309
- ` Stream<void> ` is the most specific instantiation of ` Stream ` that is a
310
- superinterface of ` T ` , unless the iteration variable has type void.
335
+ It is a compile-time error for an asynchronous for-in statement to have a
336
+ stream expression of type ` T ` such that ` Stream<void> ` is the most specific
337
+ instantiation of ` Stream ` that is a superinterface of ` T ` , unless the
338
+ iteration variable has type void.
311
339
312
340
* Hence, ` for (Object x in <void>[]) {} ` and
313
341
` await for (int x in new Stream<void>.empty()) {} ` are errors, whereas
@@ -320,13 +348,16 @@ parameter of a generic class or function is statically known to be the type
320
348
void. In this case, the bound is considered to be the built-in class
321
349
` Object ` .
322
350
323
- In Dart 2, it is a compile-time error when a method declaration _ D2_ with
324
- return type void overrides a method declaration _ D1_ whose return type is
325
- not void.
351
+ It is a compile-time error when a method declaration _ D2_ with return type
352
+ void overrides a method declaration _ D1_ whose return type is not void.
326
353
327
- * This rule is a special case of voidness preservation, which is needed in
328
- order to maintain the discipline which arises naturally from the function
329
- type subtype rules in Dart 1.x concerning void as a return type.*
354
+ * This rule is a special case of voidness preservation, which maintains the
355
+ discipline which arises naturally from the function type subtype rules in
356
+ Dart 1.x concerning void as a return type. It also matches the conceptual
357
+ interpretation that a value of type void can be anything, but it should be
358
+ discarded: This ensures that a subtype can be used where the supertype is
359
+ expected (also known as Liskov substitutability), because it is always
360
+ considered safe to ignore the value of an expression evaluation.*
330
361
331
362
## Discussion
332
363
@@ -356,6 +387,12 @@ bound as `Object`.
356
387
357
388
## Updates
358
389
390
+ * February 22nd 2018, v0.9: Added several new contexts where an
391
+ expression with static type void may be evaluated, such that pure data
392
+ transfers to a target of type void are allowed. For instance, a void
393
+ expression may be passed as an actual argument to a parameter of type
394
+ void.
395
+
359
396
* August 22nd 2017: Reworded specification of reified types to deal with
360
397
only such values which may be obtained at run time (previously mentioned
361
398
some entities which may not exist). Added one override rule.
0 commit comments