Skip to content

Commit e6cadcb

Browse files
authored
Update the declaring constructors feature specification (#4524)
This PR makes several small corrections to the declaring constructor feature specification. It also renames the document (and the feature) to 'declaring constructors', which would remove some confusion about the word 'primary': A primary constructor is one of the kinds of declaring constructors that we can create. Finally, this PR also introduces support for an abbreviated syntax with non-declaring constructors (not because it's a necessary part of the declaring constructors feature, but because it fits well with the emphasis on brevity): ```dart // Previously: class LooooooooooooooooooooooooooooooooongName { const LooooooooooooooooooooooooooooooooongName(); LooooooooooooooooooooooooooooooooongName.surName(): this(); } // Can now be: class LooooooooooooooooooooooooooooooooongName { const new(); new.surName(): this(); } ```
1 parent 39c290f commit e6cadcb

File tree

1 file changed

+80
-57
lines changed

1 file changed

+80
-57
lines changed

accepted/future-releases/primary-constructors/feature-specification.md

Lines changed: 80 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
# Declaring and Primary Constructors
1+
# Declaring Constructors
22

33
Author: Erik Ernst
44

55
Status: Accepted
66

7-
Version: 1.9
7+
Version: 1.10
88

99
Experiment flag: declaring-constructors
1010

@@ -243,9 +243,9 @@ constructor parameter is `final`.
243243

244244
In the case where the declaration is an `extension type`, the modifier
245245
`final` on the representation variable can be specified or omitted. Note
246-
that an extension type declaration is specified to use a primary
247-
constructor (in that case there is no other choice, it is in the grammar
248-
rules):
246+
that an extension type declaration is specified to use a declaring
247+
constructor (it is not supported to declare the representation variable
248+
using a normal instance variable declaration):
249249

250250
```dart
251251
// Using a primary constructor.
@@ -619,6 +619,13 @@ constructors as well.
619619
'const' <constructorName> <formalParameterList>
620620
| <declaringConstantConstructorSignature>;
621621
622+
<constructorName> ::= // Modified rule.
623+
<typeIdentifierOrNew> ('.' identifierOrNew)?;
624+
625+
<typeIdentifierOrNew> ::= // New rule.
626+
<typeIdentifier>
627+
| 'new';
628+
622629
<declaringConstantConstructorSignature> ::= // New rule.
623630
'const' 'this' ('.' <identifierOrNew>)? <declaringParameterList>;
624631
@@ -686,8 +693,8 @@ extension type declaration, together with a declaration in the body that
686693
contains a `<declaringConstructorSignature>` *(which does not contain a
687694
`<declaringParameterList>`, because that's an error)*.
688695

689-
A class declaration whose class body is `;` is treated as a class
690-
declaration whose class body is `{}`.
696+
A class or extension type declaration whose class body is `;` is treated as
697+
a declaration whose body is `{}`.
691698

692699
Let _D_ be a class, extension type, or enum declaration.
693700

@@ -732,8 +739,19 @@ superclass.*
732739
A compile-time error occurs if a `<defaultDeclaringNamedParameter>` has the
733740
modifier `required` as well as a default value.
734741

742+
*Note that the updated grammar rule for `<constructorName>` allows
743+
non-declaring constructors to use `new` where the current rules require
744+
the class name. This is not a necessary part of the declaring constructors
745+
feature, but it contributes to the overall brevity of Dart programs.*
746+
747+
735748
### Static processing
736749

750+
The ability to use `new` rather than the class name in declarations of
751+
ordinary (non-declaring) constructors is purely syntactic. The static
752+
analysis and meaning of such constructors is identical to the form that
753+
uses the class name.
754+
737755
The name of a primary constructor of the form
738756
`'const'? id1 <typeParameters>? <declaringParameterList>` is `id1` *(that
739757
is, the same as the name of the class)*.
@@ -874,12 +892,13 @@ reason for this error is that the modifier `covariant` must be specified on
874892
the declaration of `v` which is known to exist, not on the parameter.*
875893

876894
A compile-time error occurs if _p_ has both of the modifiers `covariant`
877-
and `final`. *A final instance variable cannot be covariant, because being
878-
covariant is a property of the setter.*
895+
and `final`, also if the latter is implicitly induced *(which can occur in a
896+
primary constructor of an extension type declaration)*. *A final instance
897+
variable cannot be covariant, because being covariant is a property of the
898+
setter.*
879899

880900
A compile-time error occurs if _p_ has the modifier `covariant`, but
881-
neither `var` nor `final`. *This parameter does not induce an instance
882-
variable, so there is no setter.*
901+
not `var`. *This parameter does not induce a setter.*
883902

884903
Conversely, it is not an error for the modifier `covariant` to occur on a
885904
declaring formal parameter _p_ of a declaring constructor. This extends the
@@ -890,33 +909,36 @@ constructors.
890909

891910
The semantics of the declaring constructor is found in the following steps,
892911
where _D_ is the class, extension type, or enum declaration in the program
893-
that includes a declaring constructor, and _D2_ is the result of the
912+
that includes a declaring constructor _k_, and _D2_ is the result of the
894913
derivation of the semantics of _D_. The derivation step will delete
895-
elements that amount to the declaring constructor; it will add a new
896-
constructor _k_; and it will add zero or more instance variable
914+
elements that amount to the declaring constructor. Semantically, it will
915+
add a new constructor _k2_, and it will add zero or more instance variable
897916
declarations.
898917

918+
*Adding program elements 'semantically' implies that this is not a source
919+
code transformation, it is a way to obtain semantic program elements that
920+
differ from the ones that are obtained from pre-feature declarations, but
921+
can be specified in terms of pre-feature declarations.*
922+
899923
Where no processing is mentioned below, _D2_ is identical to _D_. Changes
900924
occur as follows:
901925

902-
Assume that `p` is an optional formal parameter in _D_ which has the
903-
modifier `var` or the modifier `final` *(that is, `p` is a declaring
904-
parameter)*.
905-
906-
Assume that the combined member signature for a getter with the same name
907-
as `p` from the superinterfaces of _D_ exists, and has return type `T`. In
908-
that case the parameter `p` has declared type `T` as well.
909-
910-
*In other words, an instance variable introduced by a declaring parameter
911-
is subject to override inference, just like an explicitly declared instance
912-
variable.*
913-
914-
Otherwise, assume that `p` does not have a declared type, but it does have
915-
a default value whose static type in the empty context is a type (not a
916-
type schema) `T` which is not `Null`. In that case `p` is considered to
917-
have the declared type `T`. When `T` is `Null`, `p` is considered to have
918-
the declared type `Object?`. If `p` does not have a declared type nor a
919-
default value then `p` is considered to have the declared type `Object?`.
926+
Let `p` be a formal parameter in _k_ which has the modifier `var` or the
927+
modifier `final` *(that is, `p` is a declaring parameter)*.
928+
929+
Consider the situation where `p` has no type annotation:
930+
- if combined member signature for a getter with the same name as `p` from
931+
the superinterfaces of _D_ exists and has return type `T`, the parameter
932+
`p` has declared type `T`. If no such getter exists, but a setter with
933+
the same basename exists, with a formal parameter whose type is `T`, the
934+
parameter `p` has declared type `T`. *In other words, an instance
935+
variable introduced by a declaring parameter is subject to override
936+
inference, just like an explicitly declared instance variable.*
937+
- otherwise, if `p` is optional and has a default value whose static type
938+
in the empty context is a type `T` which is not `Null` then `p` has
939+
declared type `T`. When `T` is `Null`, `p` has declared type `Object?`.
940+
- otherwise, if `p` does not have a default value then `p` has declared
941+
type `Object?`.
920942

921943
*Dart has traditionally assumed the type `dynamic` in such situations. We
922944
have chosen the more strictly checked type `Object?` instead, in order to
@@ -932,25 +954,25 @@ this by specifying the current scope explicitly as the body scope, in spite
932954
of the fact that the declaring constructor is actually placed outside the
933955
braces that delimit the class body.*
934956

935-
Next, _k_ has the modifier `const` iff the keyword `const` occurs just
957+
Next, _k2_ has the modifier `const` iff the keyword `const` occurs just
936958
before the name of _D_ or before `this`, or if _D_ is an `enum`
937959
declaration.
938960

939-
Consider the case where _D_ is a declaring header constructor. If the name
961+
Consider the case where _k_ is a declaring header constructor. If the name
940962
`C` in _D_ and the type parameter list, if any, is followed by `.id` where
941-
`id` is an identifier then _k_ has the name `C.id`. If it is followed by
942-
`.new` then _k_ has the name `C`. If it is not followed by `.` then _k_
943-
has the name `C`. If it exists, _D2_ omits the part derived from
944-
`'.' <identifierOrNew>` that follows the name and type parameter list, if
945-
any, in _D_. Moreover, _D2_ omits the formal parameter list _L_ that
946-
follows the name, type parameter list, if any, and `.id`, if any.
963+
`id` is an identifier then _k2_ has the name `C.id`. If it is followed by
964+
`.new` then _k2_ has the name `C`. If it is not followed by `.` then _k2_
965+
has the name `C`. _D2_ omits the part derived from `'.' <identifierOrNew>`
966+
that follows the name and type parameter list in _D_, if said part exists.
967+
Moreover, _D2_ omits the formal parameter list _L_ that follows the name,
968+
type parameter list, if any, and `.id`, if any.
947969

948970
Otherwise, _D_ is a declaring body constructor. If the reserved word `this`
949-
is followed by `.id` where `id` is an identifier then _k_ has the name
950-
`C.id`. If it is followed by `.new` then _k_ has the name `C`. If it is not
951-
followed by `.` then _k_ has the name `C`.
971+
is followed by `.id` where `id` is an identifier then _k2_ has the name
972+
`C.id`. If it is followed by `.new` then _k2_ has the name `C`. If it is not
973+
followed by `.` then _k2_ has the name `C`.
952974

953-
The formal parameter list _L2_ of _k_ is identical to _L_, except that each
975+
The formal parameter list _L2_ of _k2_ is identical to _L_, except that each
954976
formal parameter is processed as follows.
955977

956978
The formal parameters in _L_ and _L2_ occur in the same order, and
@@ -968,22 +990,19 @@ positional or named parameter remains optional; if it has a default value
968990
unchanged from _L_ to _L2_ *(this is a plain, non-declaring parameter)*.
969991
- Otherwise, a formal parameter (named or positional) of the form `var T p`
970992
or `final T p` where `T` is a type and `p` is an identifier is replaced
971-
in _L2_ by `this.p`, along with its default value, if any. Next, an
972-
instance variable declaration of the form `T p;` or `final T p;` is added
973-
to _D2_. The instance variable has the modifier `final` if the parameter
974-
in _L_ has the modifier `final`, or _D_ is an `extension type`
975-
declaration, or _D_ is an `enum` declaration. In all cases, if `p` has
976-
the modifier `covariant` then this modifier is removed from the parameter
977-
in _L2_, and it is added to the instance variable declaration named `p`.
978-
979-
In every case, any DartDoc comments are copied along with the formal
980-
parameter, and in the case where an instance variable is implicitly
981-
induced, the DartDoc comment is also added to that instance variable.
993+
in _L2_ by `this.p`, along with its default value, if any. Next, a
994+
semantic instance variable declaration corresponding to the syntax `T p;`
995+
or `final T p;` is added to _D2_. It includes the modifier `final` if the
996+
parameter in _L_ has the modifier `final`, or _D_ is an `extension type`
997+
declaration and _k_ is a declaring header constructor. In all cases, if
998+
`p` has the modifier `covariant` then this modifier is removed from the
999+
parameter in _L2_, and it is added to the instance variable declaration
1000+
named `p`.
9821001

9831002
If there is an initializer list following the formal parameter list _L_
984-
then _k_ has an initializer list with the same elements in the same order.
1003+
then _k2_ has an initializer list with the same elements in the same order.
9851004

986-
Finally, _k_ is added to _D2_, and _D_ is replaced by _D2_.
1005+
Finally, _k2_ is added to _D2_, and _D_ is replaced by _D2_.
9871006

9881007
### Discussion
9891008

@@ -1017,6 +1036,10 @@ of declaration, and the constructor might be non-const).
10171036

10181037
### Changelog
10191038

1039+
1.10 - October 3, 2025
1040+
1041+
* Rename the feature to 'declaring constructors'. Fix several small errors.
1042+
10201043
1.9 - August 8, 2025
10211044

10221045
* Change the scoping such that non-late initializing expressions have the

0 commit comments

Comments
 (0)