2
2
3
3
Author: eernst@.
4
4
5
- Version: 0.5 (2018-01-04 )
5
+ Version: 0.7 (2018-04-10 )
6
6
7
7
Status: Under implementation.
8
8
9
- ** This document** is an informal specification of the * implicit creation* feature.
10
- ** The feature** adds support for omitting some occurrences of the reserved words
11
- ` new ` and ` const ` in instance creation expressions.
9
+ ** This document** is an informal specification of the * implicit creation*
10
+ feature. ** The feature** adds support for omitting some occurrences of the
11
+ reserved words ` new ` and ` const ` in instance creation expressions.
12
12
13
13
This feature specification was written with a
14
14
[ combined proposal] ( https://github.com/dart-lang/sdk/blob/master/docs/language/informal/optional-new-const.md )
@@ -68,49 +68,19 @@ reasoning, we've decided to make them optional. It will then be possible for
68
68
developers to make many expressions considerably more concise, and they can
69
69
still enforce the desired semantics as needed.
70
70
71
- Obviously, this underscores the importance of the default: When a given instance
72
- creation expression omits the keyword, should it be ` const ` or ` new ` ?
73
-
74
- ** For instance creation expressions we have chosen** to use ` const ` whenever
75
- possible, and otherwise ` new ` .
76
-
77
- This implies that ` const ` is the preferred choice for instance creation. There
78
- is a danger that ` const ` is chosen by default in some cases where this is not
79
- intended by the developer, and the affected software will have bugs which are
80
- hard to spot. In particular, ` e1 == e2 ` may evaluate to true in cases where it
81
- would have yielded false with ` new ` objects.
82
-
83
- We consider that danger to be rather small, because ` const ` can only be chosen
84
- in cases where the denoted constructor is constant, and with a class with a
85
- constant constructor it is necessary for developers to treat all accesses to its
86
- instances in such a way that the software will still work correctly even when
87
- any given instance was obtained by evaluation of a constant expression. The
88
- point is that, for such a class, we can never know for sure that any given
89
- instance is _ not_ a constant object.
90
-
91
- With composite literals such as lists and maps, a ` const ` modifier may be
92
- included in order to make it a constant expression (which will of course fail if
93
- it contains something which is not a constant expression). In this case the
94
- presence of ` const ` may again be crucial, for the same reasons as with an
95
- instance creation expression, but it may also be crucial that ` const ` is _ not_
96
- present, because the list or map will be mutated.
97
-
98
- ** For composite literals we have chosen** to implicitly introduce ` const `
99
- whenever it is required by the context.
100
-
101
- The choice to include ` const ` only when required by context (rather than
102
- whenever possible) is strictly less aggressive than the approach with instance
103
- creations. This choice is necessary because there is no way for developers to
104
- ensure that a literal like ` [1, 2] ` is mutable, if permitted by the context,
105
- other than omitting ` const ` . Furthermore, we expect this choice to be
106
- convenient in practice, because mutable data structures are used frequently. So
107
- developers must expect to write an explicit ` const ` on composite literals now
108
- and then.
109
-
110
- In summary, the implicit creation feature allows for concise construction of
111
- objects, with a slight preference for constant expressions, and it still allows
112
- developers to explicitly specify ` new ` or ` const ` , whenever needed and whenever
113
- it is considered to be good documentation.
71
+ Obviously, this underscores the importance of the default: When a given
72
+ instance creation expression omits the keyword, should it be ` const ` or
73
+ ` new ` ?
74
+
75
+ ** As a general rule** ` const ` is used whenever it is required, and
76
+ otherwise ` new ` is used. This requirement arises from the syntactic
77
+ context, based on the fact that a non-constant expression would be a
78
+ compile-time error.
79
+
80
+ In summary, the implicit creation feature allows for concise construction
81
+ of objects, and it still allows developers to explicitly specify ` new ` or
82
+ ` const ` , whenever needed and whenever it is considered to be good
83
+ documentation.
114
84
115
85
116
86
## Syntax
@@ -159,43 +129,57 @@ context*,
159
129
literal.
160
130
161
131
* This roughly means that everything which is inside a syntactically
162
- constant expression is in a constant context. Note that a ` const ` modifier
163
- which is introduced by the source code transformation does not create a
164
- constant context, it is only the explicit occurrences of ` const ` in the
165
- program that create a constant context. Also note that a ` throw ` expression
166
- is currently not allowed in a constant expression, but extensions affecting
167
- that status may be considered. A similar situation arises for function
168
- literals.*
169
-
170
- The transformation consists of two steps. In the first step, every literal
171
- list and literal map _ e_ which occurs in a constant context and does not
172
- have the modifier ` const ` is replaced by ` const ` _ e_ .
132
+ constant expression or declaration is in a constant context. Note that a
133
+ ` const ` modifier which is introduced by the source code transformation does
134
+ not create a constant context, it is only the explicit occurrences of
135
+ ` const ` in the program that create a constant context. Also note that a
136
+ ` throw ` expression is currently not allowed in a constant expression, but
137
+ extensions affecting that status may be considered. A similar situation
138
+ arises for function literals.*
139
+
140
+ * A formal parameter may have a default value, which must be a constant
141
+ expression. We have chosen to not put such default values into a constant
142
+ context. They must be constant, and it may be necessary to add the keyword
143
+ ` const ` in order to make them so. This may seem inconvenient at times, but
144
+ the rationale is that it allows for future generalizations of default value
145
+ expressions allowing them to be non-constant. Still, there is no guarantee
146
+ that such features will be added to Dart.*
147
+
148
+ * For a class which contains a constant constructor and an instance variable
149
+ which is initialized by an expression _ e_ , it is a compile-time error if
150
+ _ e_ is not constant. We have chosen to not put such initializers into a
151
+ constant context, and hence an explicit ` const ` may be required. This may
152
+ again seem inconvenient at times, but the rationale is that the reason for
153
+ the constancy requirement is non-local (the constant constructor
154
+ declaration may be many lines away from the instance variable declaration);
155
+ it may break programs in surprising and confusing ways if a constructor is
156
+ changed to be constant; and it may cause subtle bugs at run time due to the
157
+ change in identity, if such a change is made and it does not cause any
158
+ compile-time errors.*
173
159
174
160
We define * new/const insertion* as the following transformation, which will
175
161
be applied to specific parts of the program as specified below:
176
162
177
163
- if the expression _ e_ occurs in a constant context, replace _ e_ by
178
164
` const ` _ e_ ,
179
- - if the expression _ e_ does not occur in a constant context, but ` const `
180
- _ e_ is a correct constant expression, replace _ e_ by ` const ` _ e_ ,
181
165
- otherwise replace _ e_ by ` new ` _ e_ .
182
166
183
- * Note that this transformation is applied in a bottom-up order which implies
184
- that all relevant transformations have already been applied on subexpressions
185
- of _ e _ . Also note that this transformation is only applied to syntactic
186
- constructs where the outcome is a syntactically correct instance creation
187
- expression. On the other hand, the outcome may have static semantic errors,
188
- e.g., actual arguments to a constructor invocation may have wrong types
189
- because that's how the program was written. *
190
-
191
- We define * new insertion * as the following transformation, which will be
192
- applied as specified below:
193
-
194
- - replace _ e _ by ` new ` _ e _ .
195
-
196
- * We specify the second step of the transformation as based on a depth-first
197
- traversal of an abstract syntax tree (AST). This means that the program is
198
- assumed to be free of syntax errors, and when the current AST is, e.g., a
167
+ * Note that new/const insertion is just a syntactic transformation, it is
168
+ specified below where to apply it, including which syntactic constructs may
169
+ play the role of _ e _ . *
170
+
171
+ * Also note that the outcome of new/const insertion may have static semantic
172
+ errors, e.g., actual arguments to a constructor invocation may have wrong
173
+ types because that's how the program was written, or a ` const ` list may
174
+ have elements which are not constant expressions. In such cases, tools like
175
+ analyzers and compilers should emit diagnostic messages that are meaningful
176
+ in relation to the original source of the program, which might mean that
177
+ the blame is assigned to a larger syntactic construct than the one that
178
+ directly has a compile-time error after the transformation. *
179
+
180
+ * We specify the transformation as based on a depth-first traversal of an
181
+ abstract syntax tree (AST). This means that the program is assumed to be
182
+ free of syntax errors, and when the current AST is, e.g., a
199
183
` postfixExpression ` , the program as a whole has such a structure that the
200
184
current location was parsed as a ` postfixExpression ` . This is different
201
185
from the situation where we just require that a given subsequence of the
@@ -214,29 +198,6 @@ when the language supports a construct of the form `e1 e2`, etc. The reader
214
198
may prefer to view the transformation in that light, and we would then say
215
199
that we have omitted all the congruence rules.*
216
200
217
- An expression of one of the following forms must be modified in bottom-up
218
- order to be or contain a ` constantObjectExpression ` or ` newExpression `
219
- as described:
220
-
221
- With a ` postfixExpression ` _ e_ ,
222
-
223
- - if _ e_ is of the form ` constructorInvocation selector* ` , i.e.,
224
- ` typeName typeArguments '.' identifier arguments selector* ` then perform
225
- new/const insertion on the initial ` constructorInvocation ` .
226
- - if _ e_ is of the form
227
- ` typeIdentifier arguments ` where ` typeIdentifier ` denotes a class then
228
- perform new/const insertion on _ e_ .
229
- - if _ e_ is of the form
230
- ` identifier1 '.' identifier2 arguments ` where ` identifier1 ` denotes
231
- a class and ` identifier2 ` is the name of a named constructor in that class,
232
- or ` identifier1 ` denotes a prefix for a library _ L_ and ` identifier2 ` denotes
233
- a class exported by _ L_ , perform new/const insertion on _ e_ .
234
- - if _ e_ is of the form
235
- ` identifier1 '.' typeIdentifier '.' identifier2 arguments ` where
236
- ` identifier1 ` denotes a library prefix for a library _ L_ , ` typeIdentifier `
237
- denotes a class _ C_ exported by _ L_ , and ` identifier2 ` is the name of a named
238
- constructor in _ C_ , perform new/const insertion on _ e_ .
239
-
240
201
For the purposes of describing the transformation on assignable expressions
241
202
we need the following syntactic entity:
242
203
@@ -245,46 +206,82 @@ assignableExpressionTail ::=
245
206
arguments assignableSelector assignableSelectorPart*
246
207
```
247
208
248
- With an ` assignableExpression ` _ e_ ,
249
-
250
- - if _ e_ is of the form
251
- ` constructorInvocation assignableSelectorPart+ `
252
- then perform new/const insertion on the initial
253
- ` constructorInvocation ` .
254
- - if _ e_ is of the form
255
- ` typeIdentifier assignableExpressionTail `
256
- where ` typeIdentifier ` denotes a class then perform new/const insertion on
257
- the initial ` typeIdentifier arguments ` .
258
- - if _ e_ is of the form
259
- ` typeIdentifier '.' identifier assignableExpressionTail `
260
- where ` typeIdentifier ` denotes a class and ` identifier ` is the name of
261
- a named constructor in that class, or ` typeIdentifier ` denotes a prefix
262
- for a library _ L_ and ` identifier ` denotes a class exported by _ L_
263
- then perform new/const insertion on the initial
264
- ` typeIdentifier '.' identifier arguments ` .
265
- - if _ e_ is of the form
266
- ` typeIdentifier1 '.' typeIdentifier2 '.' identifier assignableExpressionTail `
267
- Where ` typeIdentifier1 ` denotes a library prefix for a library _ L_ ,
268
- ` typeIdentifier2 ` denotes a class _ C_ exported by _ L_ , and ` identifier `
269
- is the name of a named constructor in _ C_ then perform new/const insertion
270
- on the initial
271
- ` typeIdentifier1 '.' typeIdentifier2 '.' identifier arguments ` .
272
-
273
- * In short, add ` const ` wherever possible on terms that invoke a
274
- constructor, and otherwise add ` new ` . It is easy to verify that each of the
275
- replacements can be derived from ` postfixExpression ` via `primary
276
- selector* ` and similarly for ` assignableExpression`. Hence, the
277
- transformation preserves syntactic correctness.*
209
+ The transformation proceeds as follows, with three groups of situations
210
+ where a transformation is applied:
211
+
212
+ 1 . With a ` postfixExpression ` _ e_ ,
213
+
214
+ - if _ e_ is of the form ` constructorInvocation selector* ` , i.e.,
215
+ ` typeName typeArguments '.' identifier arguments selector* ` then
216
+ perform new/const insertion on the initial ` constructorInvocation ` .
217
+ - if _ e_ is of the form ` typeIdentifier arguments ` where
218
+ ` typeIdentifier ` denotes a class then perform new/const insertion on
219
+ _ e_ .
220
+ - if _ e_ is of the form ` identifier1 '.' identifier2 arguments ` where
221
+ ` identifier1 ` denotes a class and ` identifier2 ` is the name of a
222
+ named constructor in that class, or ` identifier1 ` denotes a prefix
223
+ for a library _ L_ and ` identifier2 ` denotes a class exported by _ L_ ,
224
+ perform new/const insertion on _ e_ .
225
+ - if _ e_ is of the form
226
+ ` identifier1 '.' typeIdentifier '.' identifier2 arguments `
227
+ where ` identifier1 ` denotes a library prefix for a library _ L_ ,
228
+ ` typeIdentifier ` denotes a class _ C_ exported by _ L_ , and
229
+ ` identifier2 ` is the name of a named constructor in _ C_ , perform
230
+ new/const insertion on _ e_ .
231
+
232
+ 2 . With an ` assignableExpression ` _ e_ ,
233
+
234
+ - if _ e_ is of the form
235
+ ` constructorInvocation assignableSelectorPart+ `
236
+ then perform new/const insertion on the initial
237
+ ` constructorInvocation ` .
238
+ - if _ e_ is of the form ` typeIdentifier assignableExpressionTail ` where
239
+ ` typeIdentifier ` denotes a class then perform new/const insertion on
240
+ the initial ` typeIdentifier arguments ` .
241
+ - if _ e_ is of the form
242
+ ` typeIdentifier '.' identifier assignableExpressionTail `
243
+ where ` typeIdentifier ` denotes a class and ` identifier ` is the name
244
+ of a named constructor in that class, or ` typeIdentifier ` denotes a
245
+ prefix for a library _ L_ and ` identifier ` denotes a class exported by
246
+ _ L_ then perform new/const insertion on the initial
247
+ ` typeIdentifier '.' identifier arguments ` .
248
+ - if _ e_ is of the form
249
+ `typeIdentifier1 '.' typeIdentifier2 '.' identifier
250
+ assignableExpressionTail`
251
+ where ` typeIdentifier1 ` denotes a library prefix for a library _ L_ ,
252
+ ` typeIdentifier2 ` denotes a class _ C_ exported by _ L_ , and
253
+ ` identifier ` is the name of a named constructor in _ C_ then perform
254
+ new/const insertion on the initial
255
+ ` typeIdentifier1 '.' typeIdentifier2 '.' identifier arguments ` .
256
+
257
+ 3 . If _ e_ is a literal list or a literal map which occurs in a constant
258
+ context and does not have the modifier ` const ` , it is replaced by
259
+ ` const ` _ e_ .
260
+
261
+ * In short, ` const ` is added implicitly in almost all situations where it is
262
+ required by the context, and in other situations ` new ` is added on instance
263
+ creations. It is easy to verify that each of the replacements can be
264
+ derived from ` postfixExpression ` via ` primary selector* ` and similarly for
265
+ ` assignableExpression ` . Hence, the transformation preserves syntactic
266
+ correctness.*
278
267
279
268
280
269
## Dynamic Semantics
281
270
282
- There is no dynamic semantics to specify for this feature because it is
283
- eliminated by code transformation.
271
+ There is no dynamic semantics to specify for this feature, because it is
272
+ eliminated by the code transformation.
284
273
285
274
286
275
## Revisions
287
276
277
+ - 0.7 (2018-04-10) Clarified the structure of the algorithm. Added
278
+ commentary about cases where there is no constant context even though a
279
+ constant expression is required, with a motivation for why it is so.
280
+
281
+ - 0.6 (2018-04-06) Removed "magic const" again, due to the risks
282
+ associated with this feature (getting it specified and implemented
283
+ robustly, in time).
284
+
288
285
- 0.5 (2018-01-04) Rewritten to use ` const ` whenever possible (aka "magic
289
286
const") and adjusted to specify optional const as well as optional new
290
287
together, because they are now very closely connected. This document was
0 commit comments