8000 [Feature Request] Can we have syntactic sugar for calling super constructors? · Issue #370 · dart-lang/language · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

[Feature Request] Can we have syntactic sugar for calling super constructors? #370

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

Closed
ThinkDigitalSoftware opened this issue May 22, 2019 · 10 comments
Labels
request Requests to resolve a particular developer problem

Comments

@ThinkDigitalSoftware
Copy link
ThinkDigitalSoftware commented May 22, 2019

To make calling super constructors more beautiful, can we have this syntactic sugar?
Instead of:

class TextChatMessage extends ChatMessage{
 TextChatMessage({
    @required Timestamp timestamp,
    @required String senderId,
    @required this.body,
    DocumentReference documentReference,
  }) : super(
            messageType: MessageType.string,
            senderId: senderId,
            timestamp: timestamp, documentReference:documentReference);
}

I would like to be able to write:

class TextChatMessage extends ChatMessage{
 TextChatMessage({
    @required super.timestamp,
    @required super.senderId,
    @required super.body,
    this.documentReference,
  }): super(messageType: MessageType.string); // since this type of constructor will still be an option and this variable is hard-coded and not optional.
}

One could say "well you're still using the super() syntax so what's the difference?"
To that I'd say true, but using this.messageType in constructors is also syntactic sugar, but not a requirement either.

@natebosch
Copy link
Member

What happened to messageType in the new version?

@ThinkDigitalSoftware
Copy link
Author

What happened to messageType in the new version?

I forgot to put it in. 😄 I'll edit it

@mdebbar
Copy link
mdebbar commented May 22, 2019

There's a similar issue here: #57
It would be nice to add your idea in there :)

@ThinkDigitalSoftware
Copy link
Author
ThinkDigitalSoftware commented May 22, 2019

There's a similar issue here: #57
It would be nice to add your idea in there :)

@mdebbar OK. Will a link suffice or copy and paste?

@lrhn
Copy link
Member
lrhn commented May 27, 2019

The behavior of such a short-hand should be predictable.
When we write:

TextChatMessage([super.timestamp, super.senderId, super.body} : super(messageType: ...);

it's fairly easy to define the behavior because the order of named arguments are unimportant. We can just append the super-arguments to get:

TextChatMessage([super.timestamp, super.senderId, super.body} : super(messageType: ...,
  timestamp: timestamp, senderId senderId, body: body);

It gets a little more complicated with positional parameters. Should the super.x parameters be prepended or appended to the super-invocation?

If appended:

 Gizmo(String name, super.price, super.cost) : super("Gizmo: $name");

would become

 Gizmo(String name, super.price, super.cost) : super("Gizmo: $name", price, cost);

If prepended, it would become:

 Gizmo(String name, super.price, super.cost) : super(price, cost, "Gizmo: $name");

Either makes sense. I'd say prepending is probably the best choice. Then a sub-class constructor would start with the same arguments as the super-class constructor, and extend it with more details.
It only works up to the first super-constructor argument that you need to modify instead of forward, after that, everything must be manual again.

Named parameters are easy :)

If you just want to forward all super-class parameters, then perhaps you can do:

  final String damageType;
  Gizmo(super, this.damageType);

and then super represents all super-parameters, named and positional (then you are currently restricted to not adding optional positional parameters if the superclass has a named parameter).

@eernstg
Copy link
Member
eernstg commented Sep 30, 2021

@lrhn lrhn added the request Requests to resolve a particular developer problem label Sep 30, 2021
@Levi-Lesches
Copy link

From that document:

Desugaring

This was specified without trying to desugar into existing valid Dart code.

We can desugar the desired behavior into existing Dart code, but that requires some amount of rewriting in the constructor body to enforce the “initializer-only” scope of variables introduced by initializing formals and super parameters. Example:

C(super.x, this.y, {required super.z}) : super.foo() {
  something(x, y, z);
}

could be (re)written as:

C(final TypeOfX x, final TypeOfY y, {final required TypeOfZ z}) 
   : this.y = y, super(x, z: z) {
 something(this.x, this,y, this.z);
}

The change of x, y, z to this.x, this.y, this.z is necessary to ensure the body code still references the instance variables, not the newly-introduced “normal” parameters which are visible in the body unlike the variables introduced by initializing formals and, now, super-parameters.

We so far prefer to avoid doing that kind of non-local rewriting, which means that we will need to treat this as a feature by itself, not something that can easily be “lowered” to existing code.

Specifically,

The change of x, y, z to this.x, this.y, this.z is necessary to ensure the body code still references the instance variables, not the newly-introduced “normal” parameters which are visible in the body unlike the variables introduced by initializing formals and, now, super-parameters.

To clarify, is this what's being referred to?

class A {
  int x;
  bool z;
  A.foo(this.x, {required this.z});
}

class B extends A {
  String y;
  
  /// override A.x
  @override
  int get x => super.x + 1;
  
  // B(super.x, this.y, {required super.z}) : super.foo() {
  //   something(x, y, z);
  // }
  //
  // Translates to:
  B(x, this.y, {required z}) : super.foo(x, z: z) {
    something(x);       // the parameter of the constructor
    something(this.x);  // the getter
  }
  
  void something(int a) => print(a);
}

void main() {
  A b = B(42, "Hello, World!", z: true);  // prints 42 then 43
}

@eernstg
Copy link
Member
eernstg commented Sep 30, 2021

No the point is that initializing formals (this.y) and super formals (super.x, super.z) induce a final local variable into the initializer list scope, which means that you can read their value using x, y, z in the initializer list. But in the body of the constructor those local variables are not in scope, and this means that a reference to x in the body refers to the instance variable, not the local variable, and similarly for y and z.

Cf.

\IndexCustom{formal parameter initializer scope}{%
.

@tolotrasamuel
Copy link

Isn't this already implemented?

@lrhn lrhn closed this as completed Nov 16, 2024
@lrhn
Copy link
Member
lrhn commented Nov 16, 2024

It is!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
request Requests to resolve a particular developer problem
Projects
None yet
Development

No branches or pull requests

7 participants
0