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

Proposed change to method group natural type #7364

Closed
jcouv opened this issue Jul 21, 2023 · 9 comments
Closed

Proposed change to method group natural type #7364

jcouv opened this issue Jul 21, 2023 · 9 comments
Assignees

Comments

@jcouv
Copy link
Member

jcouv commented Jul 21, 2023

Determine natural type of method group by looking scope-by-scope

Speclet: #7399

For reference:

https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md#natural-function-type

A method group has a natural type if all candidate methods in the method group have a common signature. (If the method group may include extension methods, the candidates include the containing type and all extension method scopes.)

The current behavior leads to an arguably unnecessary error in the following scenario, where an irrelevant extension method (which we have no chance of binding to) causes an error on z.

System.Action x = c.M;         // C.M()
System.Action<object> y = c.M; // E.M(C, object)
var z = new C().M;            // the delegate type could not be inferred

public class C
{
  public void M() { }
}

public static class E
{
  public static void M(this C c, object o) { }
}

When the irrelevant extension method has the right signature, we can infer the type of the delegate, but we'll still bind to the instance method (ie. it wins over the extension method).

var z = new C().M;            // C.M()

public class C
{
  public void M() { }
}

public static class E
{
  public static void M(this C c) { }
}

I would propose that we align the logic that infers the delegate type with the logic that ends up picking which method to bind to.

I would propose the following rule:

Considering each scope in turn: instance methods, then each scope of extension methods
If we have a single signature in that scope, then we can infer the function type.

Note that we'll keep the following existing behavior, where we can infer the delegate type but cannot select which method to bind to:

var z = new C().M;            // ambiguous, but we could infer the delegate type

public class C
{
}

public static class E1
{
  public static void M(this C c) { }
}
public static class E2
{
  public static void M(this C c) { }
}

One advantage of the current design is that it reduces surprises for users who change code from an explicit type to a var:
If you start with System.Action a = c.M;, the method will have been picked by overload resolution. But when you switch to var a = c.M; the type is determined in a different way which can be jarring. So requiring all signatures to match reduces the surprise on the type. But it does not mitigate the surprise on which method we actually bind to...

Relates to test plan dotnet/roslyn#52192 (lambda improvements) and dotnet/roslyn#66722 (extension types)

Design meetings

@jcouv jcouv self-assigned this Jul 21, 2023
@FaustVX
Copy link

FaustVX commented Jul 21, 2023

Does this allows us to write :

Console.WriteLine.M();

static class Ext
{
  public static void M(this Action<string> action) {}
}

@jcouv
Copy link
Member Author

jcouv commented Jul 21, 2023

Does this allows us to write :

Console.WriteLine.M();

No. That scenario will not be affected (remains disallowed).

@FaustVX
Copy link

FaustVX commented Jul 21, 2023

@jcouv

Does this allows us to write :

Console.WriteLine.M();

No. That scenario will not be affected (remains disallowed).

Is this something that may be implemented in the future ?

@CyrusNajmabadi
Copy link
Member

Yup. It's something we're actively looking into

@FaustVX
Copy link

FaustVX commented Jul 21, 2023

Yup. It's something we're actively looking into

Nice. Thanks.

@alrz
Copy link
Member

alrz commented Jul 24, 2023

A method group has a natural type if all candidate methods in the method group have a common signature

If I understand this correctly, perhaps it would allow #129?

@jcouv
Copy link
Member Author

jcouv commented Jul 24, 2023

If I understand this correctly, perhaps it would allow #129?

The proposal in OP relates to which methods are considered to determine the natural type, but does not other affect how the methods are processed. Any scenario involving a single method (such as the IsEven example linked) behaves the same in the current implementation/spec and this proposed modification. So the linked scenario would remain disallowed (it's a separate problem).

@jcouv
Copy link
Member Author

jcouv commented Jul 25, 2023

The proposal was discussed and approved in LDM 2023-07-24

@jcouv
Copy link
Member Author

jcouv commented Oct 16, 2023

Closing as duplicate of #7429 which is already in the working set and has a speclet document draft.

@jcouv jcouv closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants