-
Notifications
You must be signed in to change notification settings - Fork 207
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consider allowing "name-last" syntax for primary constructors #3299
Comments
This gets pretty close to your own idea about allowing the primary constructor to be specified in the body. That is, a class with no primary constructor in the header can have zero or one constructors with a special modifier, using // Proposed in this issue
class extends StatefulWidget
const PasswordField({
super.key,
final String? restorationId,
final Key? fieldKey,
final String? hintText,
final String? labelText,
final String? helperText,
final FormFieldSetter<String>? onSaved,
final FormFieldValidator<String>? validator,
final ValueChanged<String>? onFieldSubmitted,
final FocusNode? focusNode,
final TextInputAction? textInputAction,
}) {
@override
State<PasswordField> createState() => _PasswordFieldState();
}
// Using a `primary` constructor.
class PasswordField extends StatefulWidget {
primary const PasswordField({
super.key,
final String? restorationId,
final Key? fieldKey,
final String? hintText,
final String? labelText,
final String? helperText,
final FormFieldSetter<String>? onSaved,
final FormFieldValidator<String>? validator,
final ValueChanged<String>? onFieldSubmitted,
final FocusNode? focusNode,
final TextInputAction? textInputAction,
});
@override
State<PasswordField> createState() => _PasswordFieldState();
}
|
The difference between a primary constructor and all other constructors, is that the primary constructor also declares fields. We could let every construtor be able to declare fields, but that gets very messy and unreadable. Or we can allow any single in-body constructor to declare fields, and not need the "outside-of-body constructor syntax". And we can allow you to write Then the in-body primary constructor is just: class PasswordField extends StatefulWidget {
primary const({
super.key,
final String? restorationId,
...
final FocusNode? focusNode,
final TextInputAction? textInputAction,
});
} Then we allow the single primary constructor to be written ouside of the body, before the class PasswordField extends StatefulWidget const({
super.key,
final String? restorationId,
...
final FocusNode? focusNode,
final TextInputAction? textInputAction,
}) {
// class body
} That's basically Bob's original trailing syntax. I prefer it over moving the class name all the way to the end, because the class name is also important for reading. We can even allow an initializer list in the out-of-body primary constructor, just no constructor body: class PasswordField extends StatefulWidget const({
super.key,
final String? restorationId,
...
final FocusNode? focusNode,
final TextInputAction? textInputAction,
}) : focusDescription = focusNode == null ? "No focus" : "Has focus",
super.otherConstructor("Fixed argument") {
// class body
} And we'll allow an empty class body to be written as It makes a simple data class go from: class Name(final String firstName, final String lastName); to class Name new(final String firstName, final String lastName); And we could possibly allow omitting the About using class Foo {
final int x;
new(this.x); // Non-const, generative, unnamed
new.new(this.x); // Non-const, generative, unnamed
new.id(this.x); // Non-const, generative, named
const(this.x); // Const , generative, unnamed
const.new(this.x); // Const , generative, unnamed
const.id(this.x); // Const , generative, named
factory(int x) = Foo; // Non-const, factory , unnamed
factory(int x) = Foo; // Non-const, factory , unnamed
factory.id(int x) = Foo; // Non-const, factory , named
const factory(int x) = Foo; // Const , factory , unnamed
const factory(int x) = Foo; // Const , factory , unnamed
const factory.id(int x) = Foo; // Const , factory , named
} That basically means removing the class name, except for non-const generative constructors, where that would be removing everything, so we add back It's only for declaration, you still have to write |
Nice ideas galore! I've adjusted the PR in #3023 to support primary constructors in the body of the class / extension type / enum declaration, using the modifier class PasswordField extends StatefulWidget {
primary const PasswordField({
super.key,
String? restorationId,
Key? fieldKey,
String? hintText,
String? labelText,
String? helperText,
FormFieldSetter<String>? onSaved,
FormFieldValidator<String>? validator,
ValueChanged<String>? onFieldSubmitted,
FocusNode? focusNode,
TextInputAction? textInputAction,
});
@override
State<PasswordField> createState() => _PasswordFieldState();
} |
My 2 cents: As much as I like the idea of declaring a field and its constructor parameter in the same step, I never liked its placement in the class "signature". IMO, with So a modifier like |
One of the concerns that some people have raised around primary constructors is that with longer parameter lists, it moves the extends and implements clauses a significant distance from the start of the class. For example:
Here, the
extends StatefulWidget
clause is pushed to the bottom where it is (at least in some people's eyes) hard to find.One thing we could consider is allowing the primary constructor to be moved towards the end notably including the class name. The above would then become:
Possibly we require the constructor to be prefixed with either
new
orconst
to make parser recovery better.For shorter classes with no members besides the fields (POD classes) we allow the class body to be elided as before.
For generic classes, we allow the generic parameters to be placed on the
class
keyword in the same way that we allow generic to be attached to theextension
keyword:cc @dart-lang/language-team
The text was updated successfully, but these errors were encountered: