Description
We need to introduce an extra rule about factory constructors that are subject to augmentation: They can omit default values.
With augmentations, a factory constructor can be unimplemented. It is possible to make a late choice about the nature of this constructor (it could be redirecting or it could be non-redirecting):
class A {
A();
factory A.foo(); // Unimplemented factory constructor.
}
augment class A {
augment factory A.foo() = A;
}
class B {
B();
factory B.foo(); // Unimplemented factory constructor.
}
augment class B {
augment factory B.foo() {
return B();
}
}
We may need to introduce an extra rule about these unimplemented factory constructors which says that it is allowed for an optional parameter to omit the default value clause, even in the case where the parameter type is potentially non-nullable.
For example:
class A {
A([int i = 0]);
factory A.foo([int i]); // Currently an error; this issue proposes to allow it.
}
augment class A {
augment factory A.foo([int i]) = A; // Default value obtained from redirectee.
}
The general rules about augmentations state that no default value can be specified by an augmentation, it must always be specified by the introductory declaration (if there is to be a default value for that parameter at all).
This implies that the declaration above would not allow A.foo
to be augmented with a class body (such that it is a non-redirecting factory constructor): The parameter type cannot be modified by an augmentation, and an augmentation cannot provide a default value. In other words, the fact that there is no default value has eliminated the expressive power to make the decision about the factory being redirecting or non-redirecting, it's always forced to be redirecting.
We could allow the unimplemented factory constructor to include the default value and then ignore it (because it would be an error to have it) when the constructor is augmented to be redirecting:
class A {
A([int i = 0]);
factory A.foo([int i = 1]); // Currently allowed.
}
augment class A {
augment factory A.foo([int i]) = A; // Currently an error; this issue suggests we might allow it.
}
class B {
B();
factory B.foo([int i]); // Proposed: Allow this.
}
augment class B {
augment factory B.foo([int i = 3]) { // We could allow this.
return B();
}
}
If we do not allow this then the choice to have a default value will force the constructor to be non-redirecting.
In other words, the ability to "decide late" whether a given factory is redirecting or not will disappear as soon as there is one or more optional parameters whose type is potentially non-nullable. Of course, we can then make the declarations inconsistent: If we have two such parameters and provide a default value for exactly one of them then no augmenting declarations can be written, because they will give rise to a compile-time error no matter what.
@dart-lang/language-team, WDYT? Are you willing to allow a default value to (1) occur in an augmenting declaration, and/or (2) be declared in the introductory declaration, but then erased in the final definition because tit would be an error?