Skip to content
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

Do we allow constructors whose implementation is omitted, but provided by augmentation? #4025

Closed
eernstg opened this issue Aug 12, 2024 · 4 comments
Labels
augmentation-libraries question Further information is requested

Comments

@eernstg
Copy link
Member

eernstg commented Aug 12, 2024

This is the same kind of issue as in #4008, only for constructors.

We have the principle that keywords like factory and required must occur consistently on all elements of an augmentation declaration stack, which is also specified for constructors. For example:

const metadata = 1;

class B implements A {}

class A {
  factory A({required int i}) => B();
}

augment class A {
  @metadata
  augment factory A({required i}) => B();
}

We could generalize the grammar slightly to allow omitting the implementation, thus enabling both of the following (omitting B and metadata which are the same as above):

class A {
  factory A({required int i}); // Implementation provided in augmentation.
}

augment class A {
  @metadata
  augment factory A({required i}) => B();
}
class A {
  factory A({required int i}) => B();
}

augment class A {
  @metadata
  augment factory A({required i}); // Minimal augmentation, no need to restate the implementation.
  // We could even allow `augment factory A;`.
}

Of course, we have a variant of this example that uses a redirecting factory:

class A {
  factory A(); // Implementation provided in augmentation.
  // We won't do `factory A;`, the signature is taken from here.
}

augment class A {
  @metadata
  augment factory A() = B;
}
class A {
  factory A() = B;
}

augment class A {
  @metadata
  augment factory A(); // Minimal augmentation, no need to restate the implementation.
}

We do allow the following, which has a similar semantics (we're providing the implementation of a generative redirecting constructor by augmentation):

class A {
  A(int i);
  A.named();
}

augment class A {
  final int j;
  augment A(int i): j = i + 1;
  augment A.named(): this(25);
}

It looks like an accidental difference that the generative redirecting constructor can be introduced with no implementation (and we can't even know whether the ultimate constructor definition will be redirecting or not), but the corresponding feature for factories does not exist, just because the grammar of the language makes the "natural syntax" for this feature a syntax error.

So I'd recommend that we strive for more orthogonality and consistency at the semantic level, and introduce syntactic support for leaving out the implementations of these constructor forms.

@dart-lang/language-team, WDYT?

@eernstg
Copy link
Member Author

eernstg commented Aug 12, 2024

Note that it would also make a lot of sense to have an "empty body" syntax, which would disambiguate a number of cases where the current ambiguity (== expressive power, I guess?) exists.

// --- Without the 'omitted body' marker.
class A {
  A.named(int i); // This could be redirecting or not.
  A(); // This could be redirecting or not.
  augment A(): this.named(1); // Now we know: `A` is redirecting.
}

// --- With an 'omitted body' marker, using `?`.
class A {
  A.named(int i); // Or should we say `A.named(int i) {?}`?
  A(): this(?);
  augment A(): this.named(1); // Can choose which constructor to redirect to, with which arguments.
}

In the first approach, we'd only know that A.named is non-redirecting after having computed the definition of class A (that is, after having processed every augmentation of A).

Is it a useful piece of expressive power to allow the decision that a given constructor is redirecting or not to a very late point in time? .. or does it introduce too much ambiguity if we won't know this until "we're done merging everything"?

If we do decide that it's a useful feature then we should support it consistently, rather than just for generative constructors.

@jakemac53
Copy link
Contributor

jakemac53 commented Aug 12, 2024

Yes, the intention is to allow factory constructors with no explicit body (or redirect clause). And we allow augmenting constructors with either redirecting or non-redirecting ones, as long as they are ambiguous up to that point. Once it is not ambiguous, they can only be augmented with the same kind of constructor.

So yes, we should expand the grammar to allow factory constructors with no body, as long as some augmentation fills in either a body or redirect clause.

@eernstg
Copy link
Member Author

eernstg commented Aug 27, 2024

Note that there is a certain overlap with #4060, which is also about the ability to omit "implementation" parts of a declaration, and providing them in augmentations.

@eernstg
Copy link
Member Author

eernstg commented Sep 28, 2024

Done in #4106 and #4109.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
augmentation-libraries question Further information is requested
Projects
Development

No branches or pull requests

2 participants