Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Unified Diff: docs/language/informal/generalized-void.md

Issue 2994003002: Transferred the generalized void informal spec to docs/language/informal (Closed)
Patch Set: Review response Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: docs/language/informal/generalized-void.md
diff --git a/docs/language/informal/generalized-void.md b/docs/language/informal/generalized-void.md
new file mode 100644
index 0000000000000000000000000000000000000000..ddbc526c0f321ae5c503d61ac0d80c44edfe9339
--- /dev/null
+++ b/docs/language/informal/generalized-void.md
@@ -0,0 +1,326 @@
+## Feature: Generalized Void
+
+Author: eernst@
+
+**Status**: Under implementation.
+
+**This document** is an informal specification of the generalized support
+in Dart 1.x for the type `void`. Dart 2 will have a very similar kind of
+generalized support for `void`, without the function type subtype exception
+that this feature includes for backward compatibility in Dart 1.x. This
+document specifies the feature for Dart 1.x and indicates how Dart 2
+differs at relevant points.
+
+**The feature** described here, *generalized void*, allows for using the
+type `void` as a type annotation and as a type argument.
+
+The **motivation** for allowing the extended usage is that it helps
+developers state the intent that a particular **value should be
+ignored**. For example, a `Future<void>` may be awaited in order to satisfy
+ordering dependencies in the execution, but no useful value will be
+available at completion. Similarly, a `Visitor<void>` (where we assume the
+type argument is used to describe a value returned by the visitor) may be
+used to indicate that the visit is performed for its side-effects
+alone. The generalized void feature includes mechanisms to help developers
+avoid using such a value.
+
+In general, situations where it may be desirable to use `void` as
+a type argument arise when the corresponding formal type variable is used
+covariantly. For instance, the class `Future<T>` uses return types
+like `Future<T>` and `Stream<T>`, and it uses `T` as a parameter type of a
+callback in the method `then`.
+
+Note that is not technically dangerous to use a value of type `void`, it
+does not violate any constraints at the level of the language semantics.
+Developers just made the decision to declare that the value is useless,
+based on the program logic. Hence, there is **no requirement** for the
+generalized void mechanism to be strict and **sound**. However, it is the
+intention that the mechanism should be sufficiently strict to make the
+mechanism helpful and non-frustrating in practice.
+
+No constraints are imposed on which values may be given type `void`, so in
+that sense `void` can be considered to be just another name for the type
+`Object`, flagged as useless. Note that this is an approximate rule (in
+Dart 1.x), it fails to hold for function types.
+
+The mechanisms helping developers to avoid using values of type `void` are
+divided into **two phases**. This document specifies the first phase.
+
+The **first phase** uses restrictions which are based on syntactic criteria
+in order to ensure that direct usage of a value of type `void` is a static
+warning (in Dart 2: an error). A few exceptions are allowed, e.g., type
+casts, such that developers can explicitly make the choice to use such a
+value. The general rule is that all values of type `void` must be
+discarded.
+
+The **second phase** will deal with casts and preservation of
+voidness. Some casts will cause derived expressions to switch from having
+type `void` to having some other type, and hence those casts introduce the
+possibility that "a void value" will get passed and used. Here is an
+example:
+
+```dart
+class A<T> { T foo(); }
+A<Object> a = new A<void>(); // Violates voidness preservation.
+var x = a.foo(); // Use a "void value", with static type Object.
+```
+
+We intend to introduce a **voidness preservation analysis** (which is
+similar to a small type system) to keep track of such situations. As
+mentioned, the second phase is **not specified in this document**. Voidness
+preservation is a purely static analysis, and there are no plans to
+introduce dynamic checking for it.
+
+## Syntax
+
+The reserved word `void` remains a reserved word, but it will now be usable
+in additional contexts. Below are the grammar rules affected by this
+change. New grammar rules are marked NEW, other grammar rules are
+modified. Unchanged alternatives in a rule are shown as `...`. The grammar
+rules used as a starting point for this syntax are taken from the language
+specification as of June 2nd, 2017 (git commit 0603b18).
+
+```
+typeNotVoid ::= // NEW
+ typeName typeArguments?
+type ::= // ENTIRE RULE MODIFIED
+ typeNotVoid | 'void'
+redirectingFactoryConstructorSignature ::=
+ 'const'? 'factory' identifier ('.' identifier)?
+ formalParameterList `=' typeNotVoid ('.' identifier)?
+superclass ::=
+ 'extends' typeNotVoid
+mixinApplication ::=
+ typeNotVoid mixins interfaces?
+typeParameter ::=
+ metadata identifier ('extends' typeNotVoid)?
+newExpression ::=
+ 'new' typeNotVoid ('.' identifier)? arguments
+constObjectExpression ::=
+ 'const' typeNotVoid ('.' identifier)? arguments
+typeTest ::=
+ isOperator typeNotVoid
+typeCast ::=
+ asOperator typeNotVoid
+onPart ::=
+ catchPart block |
+ 'on' typeNotVoid catchPart? block
+typeNotVoidList ::=
+ typeNotVoid (',' typeNotVoid)*
+mixins ::=
+ 'with' typeNotVoidList
+interfaces ::=
+ 'implements' typeNotVoidList
+functionSignature ::=
+ metadata type? identifier formalParameterList
+functionFormalParameter ::=
+ metadata 'covariant'? type? identifier formalParameterList
+operatorSignature ::=
+ type? 'operator' operator formalParameterList
+getterSignature ::=
+ type? 'get' identifier
+setterSignature ::=
+ type? 'set' identifier formalParameterList
+topLevelDefinition ::=
+ ...
+ type? 'get' identifier functionBody |
+ type? 'set' identifier formalParameterList functionBody |
+ ...
+functionPrefix ::=
+ type? identifier
+```
+
+The rule for `returnType` in the grammar is deleted.
+
+*This is because we can now use `type`, which derives the same expressions
+as `returnType` used to derive. In that sense, some of these grammar
+modifications are renames. Note that the grammar contains known mistakes,
+especially concerned with the placement of `metadata`. This document makes
+no attempt to correct those mistakes, that is a separate issue.*
+
+*A complete grammar which includes support for generalized void is
+available in the file Dart.g
+from
+[https://codereview.chromium.org/2688903004/](https://codereview.chromium.org/2688903004/).*
+
+## Dynamic semantics
+
+There are no values at run time whose dynamic type is the type void.
+
+*This implies that it is never required for the getter `runtimeType` in the
+built-in class `Object` to return a reified representation of the type
+void. Note, however, that apart from the fact that usage is restricted for
+values with the type void, it is possible for an expression of type void to
+evaluate to any value. In that sense, every value has the type void, it is
+just not the only type that it has, and loosely speaking it is not the most
+specific type.*
+
+There is no value which is the reified representation of the type void at
+run time.
+
+*Syntactically, `void` cannot occur as an expression, and hence expression
+evaluation cannot directly yield such a value. However, a formal type
+parameter can be used in expressions, and the actual type argument bound to
+that formal type parameter can be the type void. That case is specified
+explicitly below. Apart from the reserved word `void` and a formal type
+parameter, no other term can denote the type void.*
+
+*Conversely, `void` cannot denote any other entity than the type void:
+`void` cannot occur as the declared name of any declaration (including
+library prefixes, types, variables, parameters, etc.). This implies that
+`void` is not subject to scoped lookup, and the name is not exported by any
+system library. Similarly, it can never be accessed using a prefixed
+expression (`p.void`). Hence, `void` has a fixed meaning everywhere in all
+Dart programs, and it can only occur as a stand-alone word.*
+
+When `void` is passed as an actual type argument to a generic class or a
+generic function, and when the type void occurs as a parameter type in a
+function type, the reified representation is equal (according to `==`) to
+the reified representation of the built-in class `Object`.
+
+*It is encouraged for an implementation to use a reified representation for
+`void` as a type argument and as a parameter type in a function type which
+is not `identical` to the reified representation of the built-in class
+`Object`, but they must be equal. This allows implementations to produce
+better diagnostic messages, e.g., in case of a runtime error.*
+
+*This treatment of the reified representation of the type void reinforces
+the understanding that "voidness" is merely a statically known flag on the
+built-in class `Object`, it is not a separate type. However, for backward
+compatibility we need to treat return types differently.*
+
+When `void` is specified as the return type of a function, the reified
+representation of the return type is left unspecified.
+
+*There is no way for a Dart program at run time to obtain a reified
+representation of that return type alone, even when the function type as a
+whole may be obtained (e.g., the function type could be evaluated as an
+expression). It is therefore not necessary to reified representation of
+such a return type.*
+
+*It may be possible to use a reflective subsystem (mirrors) to deconstruct
+a function type whose return type is the type void, but the existing design
+of the system library `dart:mirrors` already handles this case by allowing
+for a type mirror that does not have a reflected type.*
+
+Consider a type _T_ where the type void occurs as an actual type argument
+to a generic class, or as a parameter type in a function type. Dynamically,
+the more-specific-than relation (`<<`) and the dynamic subtype relation
+(`<:`) between _T_ and other types are determined by the following rule:
+the type void is treated as being the built-in class `Object`.
+
+*Dart 1.x does not support generic function types dynamically, because they
+are erased to regular function types during compilation. Hence there is no
+need to specify the the typing relations for generic function types. In
+Dart 2, the subtype relationship for generic function types follows from
+the rule that `void` is treated as `Object`.*
+
+Consider a function type _T_ where the return type is the type void. The
+dynamic more-specific-than relation, `<<`, and the dynamic subtype
+relation, `<:`, are determined by the existing rules in the language
+specification, supplemented by the above rule for handling occurrences of
+the type void other than as a return type.
+
+*This ensures backward compatibility for the cases where the type void can
+be used already today. It follows that it will be a breaking change to
+switch to a ruleset where the type void even as a return type is treated
+like the built-in class Object, i.e. when switching to Dart 2.0. However,
+the only situation where the semantics differs is as follows: Consider a
+situation where a value of type `void Function(...)` is assigned to a
+variable or parameter `x` whose type annotation is `Object Function(...)`,
+where the argument types are arbitrary, but such that the assignment is
+permitted. In that situation, in checked mode, the assignment will fail
+with the current semantics, because the type of that value is not a subtype
+of the type of `x`. The rules in this document preserve that behavior. If
+we were to consistently treat the type void as `Object` at run time (as in
+Dart 2) then this assignment would be permitted (but we would then use
+voidness preservation to detect and avoid this situation at compile time).*
+
+*The semantics of checked mode checks involving types where the type void
+occurs is determined by the semantics of subtype tests, so we do not
+specify that separately.*
+
+An instantiation of a generic class `G` is malbounded if it contains `void`
+as an actual type argument for a formal type parameter, unless that type
+parameter does not have a bound, or it has a bound which is the built-in
+class `Object`, or `dynamic`.
+
+*The treatment of malbounded types follows the current specification.*
+
+## Static Analysis
+
+For the static analysis, the more-specific-than relation, `<<`, and the
+subtype relation, `<:`, are determined by the same rules as described above
+for the dynamic semantics.
+
+*That is, the type void is considered to be equivalent to the built-in
+class `Object`, except when used as a return type, in which case it is
+effectively considered to be a proper supertype of `Object`. As mentioned,
+voidness preservation is a separate analysis which is not specified by this
+document, but it is intended to be used in the future to track "voidness"
+in types and flag implicit casts wherein information about voidness may
+indirectly be lost. With voidness preservation in place, we expect to be
+able to treat the type void as `Object` in all cases during subtype
+checks.*
+
+It is a static warning for an expression to have type void, except for the
+following situations:
+
+* In an expressionStatement `e;`, e may have type void.
+* In the initialization and increment expressions of a for-loop,
+ `for (e1; e2; e3) {..}`, `e1` and `e3` may have type void.
+* In a typeCast `e as T`, `e` may have type void.
+* In a typeTest `e is T` or `e is! T`, `e` may have type void.
+* In a parenthesized expression `(e)`, `e` may have type void.
+* In a return statement `return e;`, when the return type of the innermost
+ enclosing function is the type void, `e` may have type void.
+
+*Note that the parenthesized expression itself has type void, so it is
+again subject to the same constraints. Also note that we may not allow
+return statements returning an expression of type void in the future, but
+it is allowed here for backward compatibility.*
+
+During bounds checking, it is possible that a bound of a formal type
+parameter of a generic class or function is statically known to be the type
+void. In this case, the bound is considered to be the built-in class
+`Object`.
+
+## Discussion
+
+Expressions derived from typeCast and typeTest do not support `void` as the
+target type. We have omitted support for this situation because we consider
+it to be useless. If void is passed indirectly via a type variable `T` then
+`e as T`, `e is T`, and `e is! T` will treat `T` like `Object`. In general,
+the rationale is that the type void admits all values (because it is just
+`Object` plus a "static voidness flag"), but values of type void should be
+discarded.
+
+The treatment of bounds is delicate. We syntactically prohibit `void` as a
+bound of a formal type parameter of a generic class or function. It is
+possible to pass the type void as an actual type argument to a generic
+class, and that type argument might in turn be used as the bound of another
+formal type parameter of the class, or of a generic function in the
+class. It would be possible to make it a compile-time error to pass `void`
+as a type argument to a generic class where it will be used as a bound, but
+this would presumably require a transitive traversal of all generic classes
+and functions where the corresponding formal type parameter is passed on to
+other generic classes or functions, which would be highly brittle: A tiny
+change to a generic class or function could break code far away. So we do
+not wish to prevent formal type parameter bounds from indirectly becoming
+the type void. This motivated the decision to treat such a void-valued
+bound as `Object`.
+
+## Updates
+
+* August 9th 2017: Transferred to SDK repo, docs/language/informal.
+
+* July 16th 2017: Reformatted as a gist.
+
+* June 13th 2017: Compile-time error for using a void value was changed to
+ static warning.
+* June 12th 2017: Grammar changed extensively, to use
+ `typeNotVoid` rather than
+ `voidOrType`.
+* June 5th 2017: Added `typeCast` and
+ `typeTest` to the locations where void
+ expressions may occur.
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698