Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 85 additions & 33 deletions accepted/future-releases/primary-constructors/feature-specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Author: Erik Ernst

Status: Accepted

Version: 1.10
Version: 1.11

Experiment flag: declaring-constructors

Expand Down Expand Up @@ -575,64 +575,81 @@ constructors as well.
```ebnf
<classDeclaration> ::= // First alternative modified.
(<classModifiers> | <mixinClassModifiers>)
'class' <classNamePart> <superclass>? <interfaces>? <classBody>
'class' <classNameMaybePrimary> <superclass>? <interfaces>? <classBody>
| ...;

<primaryConstructorNoConst> ::= // New rule.
<typeIdentifier> <typeParameters>?
('.' <identifierOrNew>)? <declaringParameterList>
<primaryConstructor> ::= // New rule.
'const'? <typeWithParameters> ('.' <identifierOrNew>)?
<declaringParameterList>;

<classNamePart> ::= // New rule.
'const'? <primaryConstructorNoConst>
<classNameMaybePrimary> ::= // New rule.
<primaryConstructor>
| <typeWithParameters>;

<typeWithParameters> ::= <typeIdentifier> <typeParameters>?

<classBody> ::= // New rule.
'{' (<metadata> <classMemberDeclaration>)* '}'
'{' (<metadata> <memberDeclaration>)* '}'
| ';';

<extensionTypeDeclaration> ::= // Modified rule.
'extension' 'type' <classNamePart> <interfaces>?
'extension' 'type' <classNameMaybePrimary> <interfaces>?
<extensionTypeBody>;

<extensionTypeMemberDeclaration> ::= <classMemberDeclaration>;

<extensionTypeBody> ::=
'{' (<metadata> <extensionTypeMemberDeclaration>)* '}'
'{' (<metadata> <memberDeclaration>)* '}'
| ';';

<enumType> ::= // Modified rule.
'enum' <classNamePart> <mixins>? <interfaces>? '{'
<enumEntry> (',' <enumEntry>)* (',')?
(';' (<metadata> <classMemberDeclaration>)*)?
'enum' <classNameMaybePrimary> <mixins>? <interfaces>? '{'
<enumEntry> (',' <enumEntry>)* ','?
(';' (<metadata> <memberDeclaration>)*)?
'}';

<constructorSignature> ::= // Modified rule.
<constructorName> <formalParameterList>
<constructorName> <formalParameterList> // Old form.
| <constructorHead> <formalParameterList> // New form.
| <declaringConstructorSignature>;

<declaringConstructorSignature> ::= // New rule.
'this' ('.' <identifierOrNew>)? <declaringParameterList>?;
'this' <identifier>? <declaringParameterList>?;

<constantConstructorSignature> ::= // Modified rule.
'const' <constructorName> <formalParameterList>
'const' <constructorName> <formalParameterList> // Old form.
| 'const' <constructorHead> <formalParameterList> // New form.
| <declaringConstantConstructorSignature>;

<constructorName> ::= // Modified rule.
<typeIdentifierOrNew> ('.' identifierOrNew)?;

<typeIdentifierOrNew> ::= // New rule.
<typeIdentifier>
| 'new';
<typeIdentifier> ('.' identifierOrNew)?;

<declaringConstantConstructorSignature> ::= // New rule.
'const' 'this' ('.' <identifierOrNew>)? <declaringParameterList>;
'const' 'this' <identifier>? <declaringParameterList>;

<constructorHead> ::= // New rule.
'new' <identifier>?;

<factoryConstructorHead> ::= // New rule.
'factory' <identifier>?;

<identifierOrNew> ::=
<identifier>
| 'new'

<factoryConstructorSignature> ::= // Modified rule.
'const'? 'factory' <constructorName> <formalParameterList> // Old form.
| 'const'? <factoryConstructorHead> <formalParameterList>; // New form.

<redirectingFactoryConstructorSignature> ::= // Modified rule.
'const'? 'factory' <constructorName> <formalParameterList> '='
<constructorDesignation> // Old form.
| 'CONST'? <factoryConstructorHead> <formalParameterList> '='
<constructorDesignation>; // New form.

<constantConstructorSignature> ::= // Modified rule.
: 'const' <constructorName> <formalParameterList> // Old form.
| 'const' <constructorHead> <formalParameterList> // New form.
| <declaringConstantConstructorSignature>;

<simpleFormalParameter> ::= // Modified rule.
'covariant'? <type>? <identifier>;

Expand Down Expand Up @@ -688,28 +705,47 @@ constructors as well.
A _declaring constructor_ declaration is a declaration that contains a
`<declaringConstructorSignature>` with a `<declaringParameterList>`, or a
declaration that contains a `<declaringConstantConstructorSignature>`, or
it is a `<primaryConstructorNoConst>` in the header of a class, enum, or
extension type declaration, together with a declaration in the body that
contains a `<declaringConstructorSignature>` *(which does not contain a
it is a `<primaryConstructor>` in the header of a class, enum, or extension
type declaration, together with a declaration in the body that contains a
`<declaringConstructorSignature>` *(which does not contain a
`<declaringParameterList>`, because that's an error)*.

A class or extension type declaration whose class body is `;` is treated as
a declaration whose body is `{}`.

The grammar is ambiguous with regard to the keyword `factory`. *For
example, `factory() => C();` could be a method named `factory` with an
implicitly inferred return type, or it could be a factory constructor.*

This ambiguity is resolved as follows: When a Dart parser expects to parse
a `<memberDeclaration>`, and the first token is `factory`, it proceeds to
parse the following input as a factory constructor.

*Another special exception is introduced with factory constructors in order
to avoid breaking existing code:*

A factory constructor declaration of the form `factory C(...` where `C`
is the name of the enclosing class, mixin class, enum, or extension type is
treated as if `C` had been omitted.

*Without this special rule, such a declaration would declare a constructor
named `C.C`. With this rule it declares a constructor named `C`, which
is the same as today.*

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

A compile-time error occurs if _D_ includes a `<classNamePart>` that
contains a `<primaryConstructorNoConst>`, and the body of _D_ contains a
A compile-time error occurs if _D_ includes a `<classNameMaybePrimary>`
that contains a `<primaryConstructor>`, and the body of _D_ contains a
`<declaringConstructorSignature>` that contains a
`<declaringParameterList>`.

*It is an error to have a declaring parameter list both in the header and
in the body.*

A compile-time error occurs if _D_ includes a `<classNamePart>` that
does not contain a `<primaryConstructorNoConst>`, and the body of _D_
contains a `<declaringConstructorSignature>` that does not
contain a `<declaringParameterList>`.
A compile-time error occurs if _D_ includes a `<classNameMaybePrimary>`
that does not contain a `<primaryConstructor>`, and the body of _D_
contains a `<declaringConstructorSignature>` that does not contain a
`<declaringParameterList>`.

*It is an error to have a declaring constructor in the class body, but
no declaring parameter list, neither in the header nor in the body.*
Expand Down Expand Up @@ -1004,6 +1040,15 @@ then _k2_ has an initializer list with the same elements in the same order.

Finally, _k2_ is added to _D2_, and _D_ is replaced by _D2_.

### Language versioning

This feature is language versioned.

*It introduces a breaking change in the grammar, which implies that
developers must explicitly enable it. In particular, `factory() {}` in a
class body used to be a method declaration. With this feature it will be
a factory constructor declaration.*

### Discussion

This proposal includes support for adding the declaring header parameters to
Expand Down Expand Up @@ -1036,6 +1081,13 @@ of declaration, and the constructor might be non-const).

### Changelog

1.11 - October 30, 2025

* Introduce the new syntax for the beginning of a constructor declaration
(`new();` rather than `ClassName();`). Specify how to handle the
ambiguity involving the keyword `factory`. Clarify that this feature is
language versioned.

1.10 - October 3, 2025

* Rename the feature to 'declaring constructors'. Fix several small errors.
Expand Down