Constrained generic don't follow the same overloading rules as explicit types #2774
Replies: 9 comments
-
You are requesting a language change, so moving to |
Beta Was this translation helpful? Give feedback.
-
This would require CLR changes. |
Beta Was this translation helpful? Give feedback.
-
C# 7.3 or later allows the following code using System.Collections.Generic;
using System.Linq;
static class ClassExtensions
{
public static T FirstOrNull<T>(this IEnumerable<T> source)
where T : class
=> source.FirstOrDefault();
}
static class StructExtensions
{
public static T? FirstOrNull<T>(this IEnumerable<T> source)
where T : struct
=> source.Select(x => (T?)x).FirstOrDefault();
}
class Program
{
static void Main()
{
// ClassExtensions.FirstOrNull
new[] { "a", "b", "c" }.FirstOrNull();
// StructExtensions.FirstOrNull
new[] { 1, 2, 3 }.FirstOrNull();
}
} then the following code doesn't require CLR changes. Should it be allowed or not? using System.Collections.Generic;
static class Enumerable1
{
public static int Count<TEnumerable, TSource>(this TEnumerable source)
where TEnumerable : IEnumerable<TSource>
{
var count = 0;
checked
{
foreach (var _ in source)
count++;
return count;
}
}
}
static class Enumerable2
{
public static int Count<TEnumerable, TSource>(this TEnumerable source)
where TEnumerable : IReadOnlyCollection<TSource>
=> source.Count;
}
public static class Program
{
public static void Main()
{
var list = new List<int>();
var count = list.Count<List<int>, int>();
}
} |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
This would be a good use case for intersection types. You could make the intersection of IReadOnlyList and IList the constraint. |
Beta Was this translation helpful? Give feedback.
-
That's a different case that it's an issue even with explicit parameter types. My example is based on |
Beta Was this translation helpful? Give feedback.
-
I see. Yes, theoretically that could be fixed by continuing "bestest betterness" which was the project to narrow overload candidates and allowed "overloading" based on As for the first error, @YairHalberstadt is correct, the CLR doesn't consider generic constraints to be a part of the signature of the method and doesn't allow for overloads to be defined differing only by those generic constraints. The language can't do much about this without a CLR change, but as stated you can define the extension methods in separate classes. |
Beta Was this translation helpful? Give feedback.
-
To give you a bit more context. 9 months ago I started working a proof-of-concept trying to answer the question, what if LINQ was re-implemented based on modern .NET/C#? I ended up developing a full fledged open-source project that supports most LINQ operations with much better performance on all value-typed enumerators. Not just on particular cases, like The first error is a bit of an annoyance but easily worked around. I'd say that it's just a "good to have". The second error is much harder to work around. I had to develop a Fody weaver that automatically adds, to all iterators, overloads that explicitly call the correct extension methods. It's working but it's been hard to implement it correctly. I'm no expert in compilers and I have no idea how much work it would involve to support this feature. I think it would make things a lot simpler when trying to avoid boxing. If possible, IMHO, it would be a great addition to the language. |
Beta Was this translation helpful? Give feedback.
-
The first thing it needs is a precise specification. Once that is achieved, the implementation isn't so hard. However there are always a lot of design questions around overload resolution, which is where the real effort comes in. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Version Used:
.NET Core 3.0.0-preview7-27912-14
Steps to Reproduce:
The following code implements two overloads for
Count()
extension methods using constrained generics:Expected Behavior:
I expected the constrained generics to have the same overloading rules as when using explicit types in the parameters:
Actual Behavior:
The compilation of the code using constrained generics results in two errors:
The first error can be worked around by declaring the extension methods in separate static classes. This is annoying and not required for explicit types.
The second error can only be worked around by explicitly calling the overload. This is also annoying as it breaks the fluent syntax usually used in LINQ.
Fixing this, together with dotnet/roslyn#38450, would greatly simplify implementation and improve performance of LINQ operations.
Beta Was this translation helpful? Give feedback.
All reactions