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 |