-
Notifications
You must be signed in to change notification settings - Fork 1k
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
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
[Proposal]: Prefer spans over interfaces in overload resolution #7276
Comments
Definitely a bit concerned about this one. Will need to think through this and make sure it doesn't introduce any weirdness in corners. |
My personal preference is that we limit this to the case where |
Could we simplify this to say that when it comes to the tie breaking phase of overload resolution a |
i assume you mean a |
I mean the tie breaking rule should prefer |
I feel on the fence about this.
|
It would be nice if this worked for collection literals as well, not just for arrays. |
Found yet another case where this problem pops up when I was trying to push void AddDiagnostic(IList<Diagnostic> diagnostics, ErrorCode errorCode, params object[] arguments); To support void AddDiagnostic(IList<Diagnostic> diagnostics, ErrorCode errorCode, ReadOnlySpan<char> arg);
void AddDiagnostic(IList<Diagnostic> diagnostics, ErrorCode errorCode, params object[] arguments); This is not sufficient because then any call site which has a // Error: this call is ambiguous
AddDiagnostic(diagnostics, errorCode, "example"); The only good solution I can find is using a pair of overloads: void AddDiagnostic(IList<Diagnostic> diagnostics, ErrorCode errorCode, ReadOnlySpan<char> arg);
void AddDiagnostic(IList<Diagnostic> diagnostics, ErrorCode errorCode, params string[] arguments);
void AddDiagnostic(IList<Diagnostic> diagnostics, ErrorCode errorCode, params object[] arguments); This feels rather unfortunate to have to repeat in many places and it's not very discoverable for developers that aren't familiar with overload resolution quirks. It's also another case where we hit an ambiguity and the correct answer is to pick the |
@jaredpar based on the LDM previously (for collection expressions), we're on board with :) (in other words, i think our baby steps are complimentary with what you want, and we can come up with a fully cohesive set of rules for C#13 here :)). |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
Prefer spans over interfaces in overload resolution
Summary
Overload resolution should prefer an overload where the corresponding parameter has a span type over an overload where the parameter has a collection interface type.
Motivation
For APIs that take a collection of items, it may be useful to provide overloads for collection interfaces and for spans. Supporting collection interfaces such as
IEnumerable<T>
is particularly useful for callers using LINQ; supporting spans such asReadOnlySpan<T>
is useful for callers focused on performance.However, arrays are implicitly convertible to collection interfaces and spans, so calls with array arguments may be considered ambiguous with the current overload resolution rules.
In cases such as arrays where both overloads are applicable, overload resolution should prefer the span overload.
Detailed design
The overload resolution rules for 11.6.4.6 better conversion target could be updated with an additional rule:
Drawbacks
Preferring
ReadOnlySpan<T>
overIEnumerable<T>
in overload resolution requires choosing a user-defined conversion over an implicit reference conversion.For generic overloads such as
ImmutableArray.CreateRange<T>()
above, an array argument is only ambiguous when the generic type argument is explicit. By contrast, when the generic type argument is inferred, method type inference is required which will ignore conversions and fail to infer the type argument forReadOnlySpan<T>
.Overloads for collection interfaces and spans are still ambiguous for arrays when compiled with older compilers.
Mixing older compilers and newer TFMs is not strictly a supported scenario but it is used. Perhaps we could add a custom modifier to new overloads, so those overloads are ignored by older C# and VB compilers. What is the behavior from F#?
Alternatives
Use distinct method names rather than overloads.
This alternative is not ideal for the BCL which already uses overloads for scenarios such as collection construction where a
ReadOnlySpan<T>
overload might be useful. And using distinct names will not work for constructors.Use an extension method to overload an instance method. The extension method will only be considered when the instance method is inapplicable which avoids ambiguities when both are applicable.
This alternative prevents the compiler from choosing the better overload, however. And using extension methods will not work for constructors.
Unresolved questions
Design meetings
https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-06-19.md#prefer-spans-over-interfaces-in-overload-resolution
The text was updated successfully, but these errors were encountered: