You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -115,7 +115,18 @@ An initializing constructor for a class *C* is a generative constructor with *im
115
115
116
116
A generative constructor can be made initializing by writing `default` as a modifier before the constructor, after any `const` modifier.
117
117
118
-
Such a constructor must not declare any optional positional parameters. It may declare other parameters, and then an initializing formal is not introduced for an instance variable when the constructor declares another parameter with the same name. This allows users to explicitly initialize some fields and still have default initialization for the remaining fields. The constructor may have an initializer list and a body as normal, the `default` modifier implicitly introduces a number of named initializing formal parameters into parameter list, and it does nothing else.
118
+
An initializing constructor *must not* declare any optional positional parameters. It may declare other parameters, and then an initializing formal is not introduced for an instance variable when the constructor declares another parameter with the same name. This allows users to explicitly initialize some fields and still have default initialization for the remaining fields. The constructor may have an initializer list and a body as normal, the `default` modifier implicitly introduces a number of named initializing formal parameters into parameter list, and it does nothing else.
119
+
120
+
In short, an initializing constructor is implicitly expanded as follows:
121
+
122
+
* For each instance variable declared by the class which
123
+
* has a non-private name `x`,
124
+
* does not have an initializer expression at the declaration,
125
+
* does not have an initializer in the initializer list of the constructor,
126
+
* is not declared `late`,
127
+
* and where there is not a declared constructor parameter with the same name,
128
+
* a named parameter of the form `this.x` is added to the constructor.
129
+
* If the variable's type is potentially non-nullable, the parameter is instead `required this.x`.
119
130
120
131
#### Example
121
132
@@ -158,16 +169,18 @@ The superconstructor entry is expanded to add a number of *forwarded parameters*
158
169
- If the forwarding constructor is also an initializing constructor, then those named field-initializing parameters are added to the forwarding constructor before considering forwarding.
159
170
- If the forwarding constructor declares a parameter (including initializing constructor parameters introduced above) with the same name as a required named superconstructor parameter, it is a *compile-time error*.
160
171
- If the forwarding constructor declares a parameter (including initializing constructor parameters introduced above) with the same name as an optional named superconstructor parameter, then the superconstructor parameter is ignored and no corresponding parameter is introduced in the forwarding constructor
161
-
- If the forwarding constructor declares a parameter (including initializing constructor parameters introduced above) with the same name as a positional superconstructor parameter, call it *originalName*, then, for documentation purposes, the corresponding forwarding constructor parameter uses the name *originalName_n* where *n* is a decimal integer representing for the smallest integer greater than zero which makes the name different from any parameter name declared by the forwarding constructor or by the superconstructor.
162
-
- If the forwarding constructor declares any named parameters, including if it is an initializing constructor, then all optional positional superconstructor parameters are ignored and no corresponding parameter is introduced in the forwarding constructor..
172
+
- If the forwarding constructor declares a parameter (including initializing constructor parameters introduced above) with the same name as a positional superconstructor parameter, call it *originalName*, then, for documentation purposes, the corresponding forwarding constructor parameter uses the name *originalName$n* where *n* is a decimal integer representing the smallest integer greater than zero which makes the name different from any parameter name declared by the forwarding constructor or by the superconstructor.
173
+
- If the forwarding constructor declares any named parameters, including if it is an initializing constructor, then all optional positional superconstructor parameters are ignored and no corresponding parameter is introduced in the forwarding constructor.
163
174
- If the forwarding constructor declares any positional parameters after the superconstructor reference entry, then all optional positional superconstructor parameters are ignored and no corresponding parameter is introduced in the forwarding constructor.
164
175
- Otherwise the forwarded parameters are optional if they are optional in the superconstructor, and if so, they have the same default value, if any.
165
176
177
+
In short, we forward all superconstructor parameters that can meaningfully be added to the subclass constructor, omit those which can't, and make it an error if any of those which can't are required parameters.
178
+
166
179
Then a super-invocation is added to the initializer list where each such forwarded parameter is forwarded as a corresponding superconstructor argument.
167
180
168
-
The constructor may have an initializer list and a body as normal, excapt that the initializer list must not contain an explicit superconstructor invocation.
181
+
The constructor may have an initializer list and a body as normal, except that the initializer list must not contain an explicit superconstructor invocation.
169
182
170
-
#### Example
183
+
#### Examples
171
184
172
185
The class `ShippableParcel`above could be given an initializing constructor by writing:
173
186
@@ -195,24 +208,42 @@ class Color3DPoint extends Point {
195
208
final Color color;
196
209
final int z;
197
210
final double distanceFromOrigo;
198
-
// Expands to: Color3DPoint(this.color, int x, int y, this.z) : super(x, y);
211
+
// Expands to:
212
+
// Color3DPoint(this.color, int x, int y, this.z)
213
+
// : distanceFromOrigo = sqrt(x * x + y * y + z * z),
214
+
// super(x, y);
199
215
Color3DPoint(this.color, super, this.z)
200
216
: distanceFromOrigo = sqrt(x * x + y * y + z * z); // Cache the value.
201
217
}
202
218
```
203
219
220
+
Forwarding copies everything about the parameter, including default value.
221
+
222
+
```dart
223
+
class Complex {
224
+
final num r, i;
225
+
Complex(this.r, [this.i = 0]);
226
+
}
227
+
228
+
class ColorComplex {
229
+
final Color color;
230
+
// Expands to:
231
+
// ColorComplex(this.color, num r, [num i = 0]) : super(r, i);
232
+
ColorComplex(this.color, super);
233
+
}
234
+
```
235
+
204
236
### Default Constructors
205
237
206
238
A default constructor is a constructor which is automatically inserted if a class declares *no* constructors.
207
239
208
-
Let *C* be a class declaration with name `C` and superclass *S* with name `S`, and which declares no constructors.
209
-
210
-
It is a compile-time error if:
240
+
Let *C* be a class declaration with the name `C`, a superclass *S* with the name `S`, and which declares no constructors.
211
241
212
-
-*C* declares a private-named, non-`late`, and potentially non-nullable instance variable with no initializer expressions.
213
-
- Or in **NNBD-legacy mode**, *C* declares a private-named and final instance variable with no initializer expression.
242
+
It is a *compile-time error* if:
214
243
215
-
It is also a *compile-time error* if *S* does not declare an unnamed generative constructor.
244
+
-*C* declares a private-named, non-`late`, and potentially non-nullable instance variable with no initializer expressions. _(Such a variable needs an initializer, and since the name is private, we cannot introduce a named parameter to initialize it)._
245
+
- In **NNBD-legacy mode**, *C* declares a private-named and final instance variable with no initializer expression. _(Same, but for legacy code)._
246
+
- If *S* does not declare an unnamed generative constructor.
216
247
217
248
Otherwise let *s* be the unnamed generative constructor of *S*.
218
249
@@ -248,15 +279,15 @@ Superclass constructors with optional positional parameters are hard to forward
248
279
249
280
You only get a default constructor when you declare *no* constructors. At least it's easy to introduce the equivalent of a default constructor explicitly: `default Foo(super);`.
250
281
251
-
You only get the unnnamed constructor as default forwarded constructor. We could forward all accessible named constructors too, but it might introduce constructors that you are not interested in, or not aware of, but which your clients start using anyway. If you later add a static member with the same name, it will hide the named forwarding constructor and break client code. It's easy to get a forwarding constructor if you do want it: `default Foo.foo(super.foo);`.
282
+
You only get the unnamed constructor as default forwarded constructor. We could forward all accessible named constructors too, but it might introduce constructors that you are not interested in, or not aware of, but which your clients start using anyway. If you later add a static member with the same name, it will hide the named forwarding constructor and break client code. It's easy to get a forwarding constructor if you do want it: `default Foo.foo(super.foo);`.
252
283
253
284
It's always possible to write exactly the same constructors manually, so this change does not introduce any new expressive power. It's always possible to move away from default constructors to explicitly written constructors (except for classes used as mixins, which are always going to be highly restricted). As such, the feature has no back-end impact, it can be implemented entirely in the front-end. Back-ends may want to tree-shake unused constructors, or unused constructors parameters, though.
254
285
255
286
## Consequences
256
287
257
288
The change is *non-breaking* for default constructors. Any existing valid class that gets a default constructor with the new specification would also get a default constructor in the existing language. It will have a superclass with an unnamed constructor accepting zero arguments, and it will have no fields requiring initialization, so it too will have an unnamed constructor accepting zero arguments. Calling that constructor with no arguments will initialize any instance variable with no initializer to `null` and call the superclass unnamed constructor with the same result as calling it with zero arguments. That is exactly the same behavior as currently defined for the default constructor.
258
289
259
-
The change is non-breaking for mixin application because the semantics of forwarding constructors with no extra parameters declared matches the existing behavior for forwarding mixin application construtors.
290
+
The change is non-breaking for mixin application because the semantics of forwarding constructors with no extra parameters declared matches the existing behavior for forwarding mixin application constructors.
260
291
261
292
The added features, initializing constructors, forwarding constructors and initializing and forwarding default constructors, do introduce new ways to cause errors. We have attempted to minimize such cases, but whenever there is an implicit connection between two classes, a change to one may change the other without anybody meaning to.
262
293
@@ -280,15 +311,27 @@ This means that we *can* perhaps choose to do *less* and still be useful.
280
311
281
312
We may also want to allow forwarding constructors declared on mixins, which currently do not allow constructors. That would allow a significant number of use-cases.
282
313
283
-
We may want to allow non-nullable instance variables to be declared on mixins and still provide forwarding constructors, or allow final instance variables on mixins while still having a const forwading and initializing constructor.
314
+
We may want to allow non-nullable instance variables to be declared on mixins and still provide forwarding constructors, or allow final instance variables on mixins while still having a const forwarding and initializing constructor.
284
315
285
316
286
317
## Summary
287
318
288
319
Default constructors now have named initializing formal parameters for each public instance variable declared in the class, unless the variable is late or has an initializer. The parameter is required if the variable is potentially non-nullable (a parameter has to be required when its type is potentially non-nullable).
289
320
321
+
Example:
322
+
323
+
```dart
324
+
class Point {
325
+
final int x;
326
+
final int y;
327
+
// Implicit default Point(super);
328
+
// Expands to: Point({required this.x, required this.y}) : super();
329
+
}
330
+
```
331
+
290
332
Default constructors forward parameters to an unnamed superclass generative constructor where possible, not just to the unnamed zero-argument superclass constructor. Forwarding is not possible when the superclass constructor has a required named argument which is shadowed by a parameter of the subclass constructor (including the ones introduced to initialize fields).
291
333
292
334
This works for all classes that do not declare any constructor. Mixin applications get all constructors forwarded, which matches current behavior.
293
335
294
336
The initializing and forwarding constructor features are available for explicit use, not only as part of default constructors.
0 commit comments