| OLD | NEW |
| 1 # Optional const | 1 # Optional const |
| 2 | 2 |
| 3 Author: eernst@. | 3 Author: eernst@. |
| 4 | 4 |
| 5 Version: 0.1 (2017-08-10) | 5 Version: 0.2 (2017-08-30) |
| 6 | 6 |
| 7 Status: Under discussion | 7 Status: Under implementation. |
| 8 | 8 |
| 9 **This document** is an informal specification of the *optional const* feature. | 9 **This document** is an informal specification of the *optional const* feature. |
| 10 **The feature** adds support for omitting the reserved word `const` in list and | 10 **The feature** adds support for omitting the reserved word `const` in list and |
| 11 map literals and constant object expressions, in locations where `const` is | 11 map literals and constant object expressions, in locations where `const` is |
| 12 currently required. | 12 currently required. |
| 13 | 13 |
| 14 This informal specification is built on a | 14 This informal specification is built on a |
| 15 [combined proposal](https://github.com/dart-lang/sdk/blob/master/docs/language/i
nformal/optional-new-const.md) | 15 [combined proposal](https://github.com/dart-lang/sdk/blob/master/docs/language/i
nformal/optional-new-const.md) |
| 16 which presents optional const and several other features. | 16 which presents optional const and several other features. |
| 17 | 17 |
| 18 ## Motivation | 18 ## Motivation |
| 19 | 19 |
| 20 In Dart without optional const, complex constant expressions often contain many | 20 In Dart without optional const, complex constant expressions often contain many |
| 21 occurrences of `const` on list and map literals, and on constant object | 21 occurrences of `const` on list and map literals, and on constant object |
| 22 expressions. Subexpressions of constant expressions are themselves required to | 22 expressions. Subexpressions of constant expressions are themselves required to |
| 23 be constant expressions, and this means that `const` on a nested list or map | 23 be constant expressions, and this means that `const` on a nested list or map |
| 24 literal provides no extra information: It is a compile-time error if that | 24 literal provides no extra information: It is a compile-time error if that |
| 25 `const` is omitted. Similarly, it is a compile-time error if a nested constant | 25 `const` is omitted. Similarly, it is a compile-time error if a nested constant |
| 26 object expression is modified to use `new` rather than `const`. In that | 26 object expression is modified to use `new` rather than `const`. In that |
| 27 situation it carries no extra information whether `new` or `const` is used, and | 27 situation it carries no extra information whether `new` or `const` is used, and |
| 28 it is even possible to omit the reserved word entirely. It is also required for | 28 it is even possible to omit the reserved word entirely. It is also required for |
| 29 certain other expressions to be constant, e.g., default values on formal | 29 certain other expressions to be constant, e.g., initializing expressions for |
| 30 parameters and initializing expressions for constant variables. | 30 constant variables. |
| 31 | 31 |
| 32 In all these cases the presence of `const` is required, and hence such a | 32 In all these cases the presence of `const` is required, and hence such a |
| 33 `const` may be inferred by compilers and similar tools if it is omitted. | 33 `const` may be inferred by compilers and similar tools if it is omitted. |
| 34 | 34 |
| 35 Developers reading the source code are likely to find it easy to understand | 35 Developers reading the source code are likely to find it easy to understand |
| 36 that a required `const` was omitted and is implied, because the reason for | 36 that a required `const` was omitted and is implied, because the reason for |
| 37 the requirement is visible in the enclosing syntax: The expression where | 37 the requirement is visible in the enclosing syntax: The expression where |
| 38 `const` is inferred is a subexpression of an expression with `const`, it is | 38 `const` is inferred is a subexpression of an expression with `const` or it |
| 39 used to initialize a constant variable, or it is a default value for a formal | 39 is used in another situation where a constant value is required, e.g., to |
| 40 parameter. | 40 initialize a constant variable. |
| 41 | 41 |
| 42 In summary, tools do not need the required occurrences of `const`, and they | 42 In summary, tools do not need the required occurrences of `const`, and they |
| 43 are also unimportant for developers. Conversely, omitting required occurrences | 43 are also unimportant for developers. Conversely, omitting required occurrences |
| 44 of `const` will sometimes make large expressions substantially more concise | 44 of `const` will sometimes make large expressions substantially more concise |
| 45 and readable, and also more convenient to write. Here is an example: | 45 and readable, and also more convenient to write. Here is an example: |
| 46 | 46 |
| 47 ```dart | 47 ```dart |
| 48 const myMap = const { | 48 const myMap = const { |
| 49 "a": const [const C("able"), const C("apple"), const C("axis")], | 49 "a": const [const C("able"), const C("apple"), const C("axis")], |
| 50 "b": const [const C("banana"), const C("bold"), const C("burglary")], | 50 "b": const [const C("banana"), const C("bold"), const C("burglary")], |
| (...skipping 22 matching lines...) Expand all Loading... |
| 73 In order to support the optional const feature, the Dart grammar is modified as | 73 In order to support the optional const feature, the Dart grammar is modified as |
| 74 follows. | 74 follows. |
| 75 | 75 |
| 76 ``` | 76 ``` |
| 77 postfixExpression ::= | 77 postfixExpression ::= |
| 78 assignableExpression postfixOperator | | 78 assignableExpression postfixOperator | |
| 79 constructorInvocation | // NEW | 79 constructorInvocation | // NEW |
| 80 primary selector* | 80 primary selector* |
| 81 constructorInvocation ::= // NEW | 81 constructorInvocation ::= // NEW |
| 82 typeName typeArguments '.' identifier arguments | 82 typeName typeArguments '.' identifier arguments |
| 83 assignableExpression ::= | |
| 84 SUPER unconditionalAssignableSelector | | |
| 85 typeName typeArguments '.' identifier arguments | |
| 86 (arguments* assignableSelector)+ | // NEW | |
| 87 identifier | | |
| 88 primary (arguments* assignableSelector)+ | |
| 89 ``` | 83 ``` |
| 90 | 84 |
| 91 *A complete grammar which includes these changes is available | |
| 92 [here](https://gist.github.com/eernstg/024a997f4f8c7ef885d459c3703a35f6).* | |
| 93 | |
| 94 *Note that the alternative which is added in the rule for `assignableExpression` | |
| 95 is required in order to allow expressions which are obtained by constructing a | |
| 96 constant object expression in Dart without optional const and removing the | |
| 97 `const`. That particular case will not match any of the cases where the `const` | |
| 98 is required (because `assignableExpression` is only used in contexts which | |
| 99 cannot be constant expressions). However, this approach yields syntactic support | |
| 100 for omitting `const` in every `constantObjectExpression`, and it also allows for | |
| 101 omitting `new` from every `newExpression`, which is useful for the | |
| 102 associated | |
| 103 [optional new feature](https://gist.github.com/eernstg/7e819b44acd8dd9d71f0cc510
b618a3d).* | |
| 104 | |
| 105 *The grammar only needs to be adjusted for one case, namely invocations of named | 85 *The grammar only needs to be adjusted for one case, namely invocations of named |
| 106 constructors for generic classes. In this case we can derive expressions like | 86 constructors for generic classes. In this case we can derive expressions like |
| 107 `const Foo<int>.bar()`, and the corresponding `Foo<int>.bar()` is not derivable | 87 `const Foo<int>.bar()`, and the corresponding `Foo<int>.bar()` is not derivable |
| 108 in the same situations where the variant with `const` can be derived. In other | 88 in the same situations where the variant with `const` can be derived. In other |
| 109 words, we must add support for constructs like `Foo<int>.bar()` as part of a | 89 words, we must add support for constructs like `Foo<int>.bar()` as part of a |
| 110 `postfixExpression` and as part of an `assignableExpression`. For all other | 90 `postfixExpression`. For all other situations, the variant with `const` becomes |
| 111 situations, the variant with `const` becomes a construct which is already | 91 a construct which is already syntactically correct Dart when the `const` is |
| 112 syntactically correct Dart when the `const` is removed. For instance `const | 92 removed. For instance `const C(42)` becomes `C(42)` which is already allowed |
| 113 C(42)` becomes `C(42)` which could already be a function invocation and is hence | 93 syntactically (syntactically, it could be a function invocation).* |
| 114 already allowed syntactically.* | |
| 115 | 94 |
| 116 ## Static analysis | 95 ## Static analysis |
| 117 | 96 |
| 118 We specify a type directed source code transformation which eliminates the | 97 We specify a type directed source code transformation which eliminates the |
| 119 feature. The static analysis proceeds to work on the transformed program. | 98 feature. The static analysis proceeds to work on the transformed program. |
| 120 | 99 |
| 121 *This means that the feature is "sugar", but because of the need to refer | 100 *This means that the feature is "sugar", but because of the need to refer |
| 122 to types it could be described as static semantic sugar rather than | 101 to types it could be described as static semantic sugar rather than |
| 123 syntactic sugar. We do not specify the dynamic semantics for this feature, | 102 syntactic sugar. We do not specify the dynamic semantics for this feature, |
| 124 because the feature is eliminated in this transformation step.* | 103 because the feature is eliminated in this transformation step.* |
| 125 | 104 |
| 105 We need to treat expressions differently in different locations, hence the |
| 106 following definition: An expression _e_ is said to *occur in a constant |
| 107 context*, |
| 108 |
| 109 - if _e_ is an immediate subexpression of a constant list literal or a |
| 110 constant map literal. |
| 111 - if _e_ is an immediate subexpression of a constant object expression. |
| 112 - if _e_ is the initializing expression of a constant variable declaration. |
| 113 - if _e_ is an immediate subexpression of an expression which occurs in a |
| 114 constant context. |
| 115 |
| 116 *Note that the default value of an optional formal parameter is not a |
| 117 constant context. This choice reserves some freedom to modify the |
| 118 semantics of default values.* |
| 119 |
| 126 An expression on one of the following forms must be modified to be or | 120 An expression on one of the following forms must be modified to be or |
| 127 contain a `constantObjectExpression` as described: | 121 contain a `constantObjectExpression` as described: |
| 128 | 122 |
| 129 With a `postfixExpression` _e_, | 123 With a `postfixExpression` _e_ occurring in a constant context, |
| 130 | 124 |
| 131 - if _e_ is on the form `constructorInvocation`, i.e., | 125 - if _e_ is on the form `constructorInvocation` then replace _e_ by |
| 132 `typeName typeArguments '.' identifier arguments` then replace _e_ by | 126 `const` _e_. |
| 133 `'const' typeName typeArguments '.' identifier arguments`. | |
| 134 - if _e_ is on the form | 127 - if _e_ is on the form |
| 135 `typeIdentifier arguments` where `typeIdentifier` denotes a class then | 128 `typeIdentifier arguments` where `typeIdentifier` denotes a class then |
| 136 replace _e_ by | 129 replace _e_ by `const` _e_. |
| 137 `'const' typeIdentifier arguments`. | |
| 138 - if _e_ is on the form | 130 - if _e_ is on the form |
| 139 `identifier1 '.' identifier2 arguments` where `identifier1` denotes | 131 `identifier1 '.' identifier2 arguments` where `identifier1` denotes |
| 140 a class and `identifier2` is the name of a named constructor in that class, | 132 a class and `identifier2` is the name of a named constructor in that |
| 141 or `identifier1` denotes a prefix for a library _L_ and `identifier2` denotes | 133 class, or `identifier1` denotes a prefix for a library _L_ and |
| 142 a class exported by _L_, replace _e_ by | 134 `identifier2` denotes a class exported by _L_, replace _e_ by |
| 143 `'const' identifier1 '.' identifier2 arguments`. | 135 `const` _e_. |
| 144 - if _e_ is on the form | 136 - if _e_ is on the form |
| 145 `identifier1 '.' typeIdentifier '.' identifier2 arguments` where | 137 `identifier1 '.' typeIdentifier '.' identifier2 arguments` where |
| 146 `identifier1` denotes a library prefix for a library _L_, `typeIdentifier` | 138 `identifier1` denotes a library prefix for a library _L_, |
| 147 denotes a class _C_ exported by _L_, and `identifier2` is the name of a named | 139 `typeIdentifier` denotes a class _C_ exported by _L_, and `identifier2` |
| 148 constructor in _C_, replace _e_ by | 140 is the name of a named constructor in _C_, replace _e_ by |
| 149 `'const' identifier1 '.' typeIdentifier '.' identifier2 arguments`. | 141 `const` _e_. |
| 142 |
| 143 For a list literal _e_ occurring in a constant context, replace _e_ by |
| 144 `const` _e_. For a map literal _e_ occurring in a constant context, |
| 145 replace _e_ by `const` _e_. |
| 150 | 146 |
| 151 *In short, in these specific situations: "just add `const`". It is easy to | 147 *In short, in these specific situations: "just add `const`". It is easy to |
| 152 verify that each of the replacements can be derived from | 148 verify that each of the replacements can be derived from |
| 153 `constObjectExpression`, which can be derived from `postfixExpression` via | 149 `constObjectExpression`, which can be derived from `postfixExpression` via |
| 154 `primary selector*`; hence the transformation preserves syntactic correctness.* | 150 `primary selector*`. Hence, the transformation preserves syntactic |
| 151 correctness.* |
| 155 | 152 |
| 156 The remaining static analysis proceeds to work on the transformed program. | 153 The remaining static analysis proceeds to work on the transformed program. |
| 157 | 154 |
| 158 *It is possible that this transformation will create | 155 *It is possible that this transformation will create |
| 159 `constObjectExpressions` which violate the constraints on constant object | 156 `constObjectExpressions` which violate the constraints on constant object |
| 160 expressions. It is recommended that the error messages emitted by tools in | 157 expressions, e.g., when `const [[new A()]]` is transformed to |
| 161 response to such violations include information about the transformative | 158 `const [const [new A()]]` where the inner list is an error that was created |
| 162 step that added this `const` to the given construct and informs developers | 159 by the transformation (so the error was moved from the outer to the inner |
| 163 that they may add `new` explicitly if that matches the intention.* | 160 list). It is recommended that the error messages emitted by tools in response |
| 161 to such violations include information about the transformation.* |
| 164 | 162 |
| 165 ## Dynamic Semantics | 163 ## Dynamic Semantics |
| 166 | 164 |
| 167 There is no dynamic semantics to specify for this feature because it is | 165 There is no dynamic semantics to specify for this feature because it is |
| 168 eliminated by code transformation. | 166 eliminated by code transformation. |
| 169 | 167 |
| 170 | 168 |
| 171 ## Revisions | 169 ## Revisions |
| 172 | 170 |
| 173 - 0.1 (2017-08-10) Stand-alone proposal for optional const created, using | 171 - 0.2 (2017-08-30) Updated the document to specify the previously missing |
| 174 version 0.8 of the combined proposal | 172 transformations for composite literals (lists and maps), and to specify a |
| 173 no-magic approach (where no `const` is introduced except when forced by |
| 174 the syntactic context). |
| 175 |
| 176 - 0.1 (2017-08-10) Stand-alone informal specification for optional const |
| 177 created, using version 0.8 of the combined proposal |
| 175 [optional-new-const.md](https://github.com/dart-lang/sdk/blob/master/docs/lang
uage/informal/optional-new-const.md) | 178 [optional-new-const.md](https://github.com/dart-lang/sdk/blob/master/docs/lang
uage/informal/optional-new-const.md) |
| 176 as the starting point. | 179 as the starting point. |
| OLD | NEW |