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

Allow an extension instance member to be resolved implicitly even when it clashes with a static member of the on-type #4113

Closed
eernstg opened this issue Sep 30, 2024 · 2 comments
Labels
extension-methods small-feature A small feature which is relatively cheap to implement.

Comments

@eernstg
Copy link
Member

eernstg commented Sep 30, 2024

See dart-lang/sdk#56818 for a more detailed analysis.

I'd recommend that we adjust the language specification such that an extension is applicable even in the case where the on-type has a static member with the same member name.

class A {
  static void foo() {}
  void bar1() => foo(); // Calls the static member `A.foo`.
}

extension E on A {
  void foo() {}
  void bar2() => foo(); // Calls the extension instance member `E.foo`.
}

void main() {
  A.foo(); // OK, calls the static method.
  A().foo(); // OK, calls the extension instance method.
}

This can be done by adding one word to the relevant rule:

The type $S$ does not have an instance member with the basename $m$,
and $S$ is neither \DYNAMIC{} nor \code{Never}.

With the current rule, A().foo() is an error.

The feature specification which was used as the vehicle to introduce this language mechanism uses the same wording, which means that the rule has been in effect all the time where this feature has been part of the language.

However, it still seems likely that the intended behavior is to accept A().foo() in the above example, and the analysis in dart-lang/sdk#56818 doesn't reveal any difficulties in allowing it.

The change has no associated implementation effort because the analyzer and the CFE already have the proposed behavior. This also makes the change non-breaking. It's basically just fixing a mistake in the specification.

@dart-lang/language-team, WDYT, do you see any dangers or reasons not to perform this adjustment?

@lrhn
Copy link
Member

lrhn commented Sep 30, 2024

Ship it.
It's a spec bug, so we should just fix it.
It's in the original feature specification too, so it's not new, and yet implementations did the right thing, so it's at least not very confusing.

The intent has always been that if an instance member access e.foo... is invalid because the type interface of the static type of e does not have a foo member, then an extension member may be applicable.
Static members are never relevant, so it's a mistake that the spec said "does not have a member" where it should have said "does not have an instance member".

(The original feature spec says exactly the same thing: "The type S does not have a member with the basename m.". When we talk about types having members, we usually mean instance members. You can't access static members through types ... but you can through type aliases, and that's already weird. In any case it could, and should, just have said "instance member" and been clear about it.)

@eernstg
Copy link
Member Author

eernstg commented Oct 2, 2024

Very good! The language specification has been updated, and static members should be ignored. That is, extension applicability can only be prevented by an instance member of the static type of the syntactic receiver, it doesn't matter whether there's a static member with the same basename.

@eernstg eernstg closed this as completed Oct 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
extension-methods small-feature A small feature which is relatively cheap to implement.
Projects
None yet
Development

No branches or pull requests

2 participants