Overloaded method-group argument confuses overload resolution? - c#

The following call to the overloaded Enumerable.Select method:
var itemOnlyOneTuples = "test".Select<char, Tuple<char>>(Tuple.Create);
fails with an ambiguity error (namespaces removed for clarity):
The call is ambiguous between the following methods or properties:
'Enumerable.Select<char,Tuple<char>>
(IEnumerable<char>,Func<char,Tuple<char>>)'
and
'Enumerable.Select<char,Tuple<char>>
(IEnumerable<char>, Func<char,int,Tuple<char>>)'
I can certainly understand why not specifying the type-arguments explicitly would result in an ambiguity (both the overloads would apply), but I don't see one after doing so.
It appears clear enough to me that the intention is to call the first overload, with the method-group argument resolving to Tuple.Create<char>(char). The second overload should not apply because none of the Tuple.Create overloads can be converted to the expected Func<char,int,Tuple<char>> type. I'm guessing the compiler is confused by Tuple.Create<char, int>(char, int), but its return-type is wrong: it returns a two-tuple, and is hence not convertible to the relevant Func type.
By the way, any of the following makes the compiler happy:
Specifying a type-argument for the method-group argument: Tuple.Create<char> (Perhaps this is actually a type-inference issue?).
Making the argument a lambda-expression instead of a method-group: x => Tuple.Create(x). (Plays well with type-inference on the Select call).
Unsurprisingly, trying to call the other overload of Select in this manner also fails:
var itemIndexTwoTuples = "test".Select<char, Tuple<char, int>>(Tuple.Create);
What's the exact problem here?

First off, I note that this is a duplicate of:
Why is Func<T> ambiguous with Func<IEnumerable<T>>?
What's the exact problem here?
Thomas's guess is essentially correct. Here are the exact details.
Let's go through it a step at a time. We have an invocation:
"test".Select<char, Tuple<char>>(Tuple.Create);
Overload resolution must determine the meaning of the call to Select. There is no method "Select" on string or any base class of string, so this must be an extension method.
There are a number of possible extension methods for the candidate set because string is convertible to IEnumerable<char> and presumably there is a using System.Linq; in there somewhere. There are many extension methods that match the pattern "Select, generic arity two, takes an IEnumerable<char> as the first argument when constructed with the given method type arguments".
In particular, two of the candidates are:
Enumerable.Select<char,Tuple<char>>(IEnumerable<char>,Func<char,Tuple<char>>)
Enumerable.Select<char,Tuple<char>>(IEnumerable<char>,Func<char,int,Tuple<char>>)
Now, the first question we face is are the candidates applicable? That is, is there an implicit conversion from each supplied argument to the corresponding formal parameter type?
An excellent question. Clearly the first argument will be the "receiver", a string, and it will be implicitly convertible to IEnumerable<char>. The question now is whether the second argument, the method group "Tuple.Create", is implicitly convertible to formal parameter types Func<char,Tuple<char>>, and Func<char,int, Tuple<char>>.
When is a method group convertible to a given delegate type? A method group is convertible to a delegate type when overload resolution would have succeeded given arguments of the same types as the delegate's formal parameter types.
That is, M is convertible to Func<A, R> if overload resolution on a call of the form M(someA) would have succeeded, given an expression 'someA' of type 'A'.
Would overload resolution have succeeded on a call to Tuple.Create(someChar)? Yes; overload resolution would have chosen Tuple.Create<char>(char).
Would overload resolution have succeeded on a call to Tuple.Create(someChar, someInt)? Yes, overload resolution would have chosen Tuple.Create<char,int>(char, int).
Since in both cases overload resolution would have succeeded, the method group is convertible to both delegate types. The fact that the return type of one of the methods would not have matched the return type of the delegate is irrelevant; overload resolution does not succeed or fail based on return type analysis.
One might reasonably say that convertibility from method groups to delegate types ought to succeed or fail based on return type analysis, but that's not how the language is specified; the language is specified to use overload resolution as the test for method group conversion, and I think that's a reasonable choice.
Therefore we have two applicable candidates. Is there any way that we can decide which is better than the other? The spec states that the conversion to the more specific type is better; if you have
void M(string s) {}
void M(object o) {}
...
M(null);
then overload resolution chooses the string version because string is more specific than object. Is one of those delegate types more specific than the other? No. Neither is more specific than the other. (This is a simplification of the better-conversion rules; there are actually lots of tiebreakers, but none of them apply here.)
Therefore there is no basis to prefer one over the other.
Again, one could reasonably say that sure, there is a basis, namely, that one of those conversions would produce a delegate return type mismatch error and one of them would not. Again, though, the language is specified to reason about betterness by considering the relationships between the formal parameter types, and not about whether the conversion you've chosen will eventually result in an error.
Since there is no basis upon which to prefer one over the other, this is an ambiguity error.
It is easy to construct similar ambiguity errors. For example:
void M(Func<int, int> f){}
void M(Expression<Func<int, int>> ex) {}
...
M(x=>Q(++x));
That's ambiguous. Even though it is illegal to have a ++ inside an expression tree, the convertibility logic does not consider whether the body of a lambda has something inside it that would be illegal in an expression tree. The conversion logic just makes sure that the types check out, and they do. Given that, there's no reason to prefer one of the M's over the other, so this is an ambiguity.
You note that
"test".Select<char, Tuple<char>>(Tuple.Create<char>);
succeeds. You now know why. Overload resolution must determine if
Tuple.Create<char>(someChar)
or
Tuple.Create<char>(someChar, someInt)
would succeed. Since the first one does and the second one does not, the second candidate is inapplicable and eliminated, and is therefore not around to become ambiguous.
You also note that
"test".Select<char, Tuple<char>>(x=>Tuple.Create(x));
is unambiguous. Lambda conversions do take into account the compatibility of the returned expression's type with the target delegate's return type. It is unfortunate that method groups and lambda expressions use two subtly different algorithms for determining convertibility, but we're stuck with it now. Remember, method group conversions have been in the language a lot longer than lambda conversions; had they been added at the same time, I imagine that their rules would have been made consistent.

I'm guessing the compiler is confused by Tuple.Create<char, int>(char, int), but its return-type is wrong: it returns a two-tuple.
The return type isn't part of the method signature, so it isn't considered during overload resolution; it's only verified after an overload has been picked. So as far as the compiler knows, Tuple.Create<char, int>(char, int) is a valid candidate, and it is neither better nor worse than Tuple.Create<char>(char), so the compiler can't decide.

Related

Why doesn't the C# compiler consider this generic type inference ambiguous?

Given the following class:
public static class EnumHelper
{
//Overload 1
public static List<string> GetStrings<TEnum>(TEnum value)
{
return EnumHelper<TEnum>.GetStrings(value);
}
//Overload 2
public static List<string> GetStrings<TEnum>(IEnumerable<TEnum> value)
{
return EnumHelper<TEnum>.GetStrings(value);
}
}
What rules are applied to select one of its two generic methods? For example, in the following code:
List<MyEnum> list;
EnumHelper.GetStrings(list);
it ends up calling EnumHelper.GetStrings<List<MyEnum>>(List<MyEnum>) (i.e. Overload 1), even though it seems just as valid to call EnumHelper.GetStrings<MyEnum>(IEnumerable<MyEnum>) (i.e. Overload 2).
For example, if I remove overload 1 entirely, then the call still compiles fine, instead choosing the method marked as overload 2. This seems to make generic type inference kind of dangerous, as it was calling a method which intuitively seems like a worse match. I'm passing a List/Enumerable as the type, which seems very specific and seems like it should match a method with a similar parameter (IEnumerable<TEnum>), but it's choosing the method with the more generic, generic parameter (TEnum value).
What rules are applied to select one of its two generic methods?
The rules in the specification - which are extremely complex, unfortunately. In the ECMA C# 5 standard, the relevant bit starts at section 12.6.4.3 ("better function member").
However, in this case it's relatively simple. Both methods are applicable, with type inference occurring separately for each method:
For method 1, TEnum is inferred to be List<MyEnum>
For method 2, TEnum is inferred to be MyEnum
Next the compiler starts checking the conversions from arguments to parameters, to see whether one conversion is "better" than the other. That goes into section 12.6.4.4 ("better conversion from expression").
At this point we're considering these conversions:
Overload 1: List<MyEnum> to List<MyEnum> (as TEnum is inferred to be List<MyEnum>)
Overload 2: List<MyEnum> to IEnumerable<MyEnum> (as TEnum is inferred to be MyEnum)
Fortunately, the very first rule helps us here:
Given an implicit conversion C1 that converts from an expression E to a type T1, and an implicit conversion C2 that converts from an expression E to a type T2, C1 is a better conversion than C2 if at least one of the following holds:
E has a type S and an identity conversion exists from S to T1 but not from S to T2
There is an identity conversion from List<MyEnum> to List<MyEnum>, but there isn't an identity conversion from List<MyEnum> to IEnumerable<MyEnum>, therefore the first conversion is better.
There aren't any other conversions to consider, therefore overload 1 is seen as the better function member.
Your argument about "more general" vs "more specific" parameters would be valid if this earlier phase had ended in a tie-break, but it doesn't: "better conversion" for arguments to parameters is considered before "more specific parameters".
In general, both overload resolution is incredibly complicated. It has to take into account inheritance, generics, type-less arguments (e.g. the null literal, the default literal, anonymous functions), parameter arrays, all the possible conversions. Almost any time a new feature is added to C#, it affects overload resolution :(

Method overloaded with "params" keyword behavior [duplicate]

Say I have the following methods:
public static void MyCoolMethod(params object[] allObjects)
{
}
public static void MyCoolMethod(object oneAlone, params object[] restOfTheObjects)
{
}
If I do this:
MyCoolMethod("Hi", "test");
which one gets called and why?
It's easy to test - the second method gets called.
As to why - the C# language specification has some pretty detailed rules about how ambiguous function declarations get resolved. There are lots of questions on SO surrounding interfaces, inheritance and overloads with some specific examples of why different overloads get called, but to answer this specific instance:
C# Specification - Overload Resolution
7.5.3.2 Better function member
For the purposes of determining the
better function member, a
stripped-down argument list A is
constructed containing just the
argument expressions themselves in the
order they appear in the original
argument list.
Parameter lists for each of the
candidate function members are
constructed in the following way:
The expanded form is used if
the function member was applicable
only in the expanded form.
Optional parameters with no
corresponding arguments are removed
from the parameter list
The parameters are reordered
so that they occur at the same
position as the corresponding argument
in the argument list.
And further on...
In case the parameter type sequences {P1, P2, …, PN} and {Q1, Q2, …, QN} are equivalent > (i.e. each Pi has an identity conversion to the corresponding Qi), the following
tie-breaking rules are applied, in order, to determine the better function member.
If MP is a non-generic method and MQ is a generic method, then MP is better than MQ.
Otherwise, if MP is applicable in its normal form and MQ has a params array and is
applicable only in its expanded form, then MP is better than MQ.
Otherwise, if MP has more declared parameters than MQ, then MP is better than MQ.
This can occur if both methods have params arrays and are applicable only in their
expanded forms.
The bolded tie-breaking rule seems to be what is applying in this case. The specification goes into detail about how the params arrays are treated in normal and expanded forms, but ultimately the rule of thumb is that the most specific overload will be called in terms of number and type of parameters.
The second one, the compiler will first try to resolve against explicitly declared parameters before falling back on the params collection.
This overload is tricky...
MyCoolMethod("Hi", "test") obviously calls the 2nd overload, but
MyCoolMethod("Hi"); also calls the 2nd overload. I tested this.
Maybe since both of the inputs are objects, the compiler assume anything passed in will be an array of objects and completely ignores the 1st overload.
It probably has to do with the Better function member resolution mentioned by womp
http://msdn.microsoft.com/en-us/library/aa691338(v=VS.71).aspx

Why is the compiler not able to infer the type of the method? [duplicate]

Consider
void Main()
{
var list = new[] {"1", "2", "3"};
list.Sum(GetValue); //error CS0121
list.Sum(s => GetValue(s)); //works !
}
double GetValue(string s)
{
double val;
double.TryParse(s, out val);
return val;
}
The description for the CS0121 error is
The call is ambiguous between the following methods or properties:
'System.Linq.Enumerable.Sum<string>(System.Collections.Generic.IEnumerable<string>,
System.Func<string,decimal>)' and
'System.Linq.Enumerable.Sum<string>(System.Collections.Generic.IEnumerable<string>,
System.Func<string,decimal?>)'
What I don't understand is, what information does s => GetValue(s) give the compiler that simply GetValue doesn't - isn't the latter syntactic sugar for the former ?
Mark's answer is correct but could use a bit more explanation.
The problem is indeed due to a subtle difference between how method groups are handled and how lambdas are handled.
Specifically, the subtle difference is that a method group is considered to be convertible to a delegate type solely on the basis of whether the arguments match, not also on the basis of whether the return type matches. Lambdas check both the arguments and the return type.
The reason for this odd rule is that method group conversions to delegates are essentially a solution of the overload resolution problem. Suppose D is the delegate type double D(string s) and M is a method group containing a method that takes a string and returns a string. When resolving the meaning of a conversion from M to D, we do overload resolution as if you had said M(string). Overload resolution would pick the M that takes a string and returns a string, and so M is convertible to that delegate type even though the conversion will result in an error later. Just as "regular" overload resolution would succeed if you said "string s = M(null);" -- overload resolution succeeds, even though that causes a conversion failure later.
This rule is subtle and a bit weird. The upshot of it here is that your method group is convertible to all the different delegate types that are the second arguments of every version of Sum that takes a delegate. Since no best conversion can be found, the overload resolution on method group Sum is ambiguous.
Method group conversions rules are plausible but a bit odd in C#. I am somewhat vexed that they are not consistent with the more "intuitively correct" lambda conversions.
s => GetValue(s) is a lambda expression and GetValue is a method group, which is a completely different thing. They can both be considered syntactic sugar for new Func<string,double>(...) but the only way they are related to each other is that the lambda expression includes a call to GetValue(). When it comes to converting to a delegate, method groups have different conversion rules than lambda expressions with respect to return types. See Why is Func<T> ambiguous with Func<IEnumerable<T>>? and Overloaded method-group argument confuses overload resolution?.

Why can't the compiler tell the better conversion target in this overload resolution case? (covariance)

Understanding the C# Language Specification on overload resolution is clearly hard, and now I am wondering why this simple case fails:
void Method(Func<string> f)
{
}
void Method(Func<object> f)
{
}
void Call()
{
Method(() => { throw new NotSupportedException(); });
}
This gives compile-time error CS0121, The call is ambiguous between the following methods or properties: followed by my two Method function members (overloads).
What I would have expected was that Func<string> was a better conversion target than Func<object>, and then the first overload should be used.
Since .NET 4 and C# 4 (2010), the generic delegate type Func<out TResult> has been covariant in TResult, and for that reason an implicit conversion exists from Func<string> to Func<object> while clearly no implicit conversion can exist from Func<object> to Func<string>. So it would make Func<string> the better conversion target, and the overload resolution should pick the first overload?
My question is simply: What part of the C# Spec am I missing here?
Addition: This works fine:
void Call()
{
Method(null); // OK!
}
My question is simply: What part of the C# Spec am I missing here?
Summary:
You have found a minor known bug in the implementation.
The bug will be preserved for backwards compatibility reasons.
The C# 3 specification contained an error regarding how the "null" case was to be handled; it was fixed in the C# 4 specification.
You can reproduce the buggy behavior with any lambda where the return type cannot be inferred. For example: Method(() => null);
Details:
The C# 5 specification says that the betterness rule is:
If the expression has a type then choose the better conversion from that type to the candidate parameter types.
If the expression does not have a type and is not a lambda, choose the conversion to the type that is better.
If the expression is a lambda then first consider which parameter type is better; if neither is better and the delegate types have identical parameter lists then consider the relationship between the inferred return type of the lambda and the return types of the delegates.
So the intended behaviour is: first the compiler should check to see if one parameter type is clearly better than the other, regardless of whether the argument has a type. If that doesn't resolve the situation and the argument is a lambda, then check to see which of the inferred return type converted to the parameters' delegate types' return type is better.
The bug in the implementation is the implementation doesn't do that. Rather, in the case where the argument is a lambda it skips the type betterness check entirely and goes straight to the inferred return type betterness check, which then fails because there is no inferred return type.
My intention was to fix this for Roslyn. However, when I went to implement this, we discovered that making the fix caused some real-world code to stop compiling. (I do not recall what the real-world code was and I no longer have access to the database that holds the compatibility issues.) We therefore decided to maintain the existing small bug.
I note that the bug was basically impossible before I added delegate variance in C# 4; in C# 3 it was impossible for two different delegate types to be more or less specific, so the only rule that could apply was the lambda rule. Since there was no test in C# 3 that would reveal the bug, it was easy to write. My bad, sorry.
I note also that when you start throwing expression tree types into the mix, the analysis gets even more complicated. Even though Func<string> is better than Func<object>, Expression<Func<string>> is not convertible to Expression<Func<object>>! It would be nice if the algorithm for betterness was agnostic with respect to whether the lambda was going to an expression tree or a delegate, but it is in some ways not. Those cases get complicated and I don't want to labour the point here.
This minor bug is an object lesson in the importance of implementing what the spec actually says and not what you think it says. Had I been more careful in C# 3 to ensure that the code matched the spec then the code would have failed on the "null" case and it would then have been clear earlier that the C# 3 spec was wrong. And the implementation does the lambda check before the type check, which was a time bomb waiting to go off when C# 4 rolled around and suddenly that became incorrect code. The type check should have been done first regardless.
Well, you are right. What causes problem here is the delegate you are passing as an argument. It has no explicit return type, you are just throwing an exception. Exception is basically an object but it is not considered as a return type of a method. Since there is no return call following the exception throw, compiler is not sure what overload it should use.
Just try this
void Call()
{
Method(() =>
{
throw new NotSupportedException();
return "";
});
}
No problem with choosing an overload now because of explicitly stated type of an object passed to a return call. It does not matter that the return call is unreachable due to the exception throw, but now the compiler knows what overload it should use.
EDIT:
As for the case with passing null, frenkly, I don't know the answer.

Delegate as first param to an Extension Method

Ladies and Gents,
I recently tried this experiment:
static class TryParseExtensions
{
public delegate bool TryParseMethod<T>(string s, out T maybeValue);
public static T? OrNull<T>(this TryParseMethod<T> tryParser, string s) where T:struct
{
T result;
return tryParser(s, out result) ? (T?)result : null;
}
}
// compiler error "'int.TryParse(string, out int)' is a 'method', which is not valid in the given context"
var result = int.TryParse.OrNull("1"); // int.TryParse.OrNull<int>("1"); doesnt work either
// compiler error: type cannot be infered....why?
var result2 = TryParseExtensions.OrNull(int.TryParse, "2");
// works as expected
var result3 = TryParseExtensions.OrNull<int>(int.TryParse, "3");
var result4 = ((TryParseExtensions.TryParseMethod<int>)int.TryParse).OrNull("4");
I am wondering two things:
Why can the compiler not infer the "int" type parameter?
Do I understand correctly that extensions methods do not get discovered on Delegate types, as I guess they arent really of that type (but are a "Method") that only happen to match the delegates signature? As such a cast solves this. Would it be infeasable to enable scenario 1 to work (not this one specifically of course, but in general)? I guess from a language/compiler perspective and would it actually be useful, or am I just (attempting to) wildly abusing things here?
Looking forward to some insights. Thnx
You have a number of questions here. (In the future I would recommend that when you have multiple questions, split them up into multiple questions rather than one posting with several questions in it; you'll probably get better responses.)
Why can the compiler not infer the "int" type parameter in:
TryParseExtensions.OrNull(int.TryParse, "2");
Good question. Rather than answer that here, I refer you to my 2007 article which explains why this did not work in C# 3.0:
http://blogs.msdn.com/b/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not-work-on-member-groups.aspx
Summing up: fundamentally there is a chicken-and-egg problem here. We must do overload resolution on int.TryParse to determine which overload of TryParse is the intended one (or, if none of them work, what the error is.) Overload resolution always tries to infer from arguments. In this case though, it is precisely the type of the argument that we are attempting to infer.
We could come up with a new overload resolution algorithm that says "well, if there's only one method in the method group then pick that one even if we don't know what the arguments are", but that seems weak. It seems like a bad idea to special-case method groups that have only one method in them because that then penalizes you for adding new overloads; it can suddenly be a breaking change.
As you can see from the comments to that article, we got a lot of good feedback on it. The best feedback was got was basically "well, suppose type inference has already worked out the types of all the argument and it is the return type that we are attempting to infer; in that case you could do overload resolution". That analysis is correct, and changes to that effect went into C# 4. I talked about that a bit more here:
http://blogs.msdn.com/b/ericlippert/archive/2008/05/28/method-type-inference-changes-part-zero.aspx
Do I understand correctly that extensions methods do not get discovered on delegate types, as I guess they arent really of that type (but are a "Method") that only happen to match the delegates signature?
Your terminology is a bit off, but your idea is correct. We do not discover extension methods when the "receiver" is a method group. More generally, we do not discover extension methods when the receiver is something that lacks its own type, but rather takes on a type based on its context: method groups, lambdas, anonymous methods and the null literal all have this property. It would be really bizarre to say null.Whatever() and have that call an extension method on String, or even weirder, (x=>x+1).Whatever() and have that call an extension method on Func<int, int>.
The line of the spec which describes this behaviour is :
An implicit identity, reference or boxing conversion [must exist] from [the receiver expression] to the type of the first parameter [...].
Conversions on method groups are not identity, reference or boxing conversions; they are method group conversions.
Would it be infeasable to enable scenario 1 to work (not this one specifically of course, but in general)? I guess from a language/compiler perspective and would it actually be useful, or am I just (attempting to) wildly abusing things here?
It is not infeasible. We've got a pretty smart team here and there's no theoretical reason why it is impossible to do so. It just doesn't seem to us like a feature that adds more value to the language than the cost of the additional complexity.
There are times when it would be useful. For example, I'd like to be able to do this; suppose I have a static Func<A, R> Memoize<A, R>(this Func<A, R> f) {...}:
var fib = (n=>n<2?1:fib(n-1)+fib(n-2)).Memoize();
Instead of what you have to write today, which is:
Func<int, int> fib = null;
fib = n=>n<2?1:fib(n-1)+fib(n-2);
fib = fib.Memoize();
But frankly, the additional complexity the proposed feature adds to the language is not paid for by the small benefit in making the code above less verbose.
The reason for the first error:
int.TryParse is a method group, not an object instance of any type. Extension methods can only be called on object instances. That's the same reason why the following code is invalid:
var s = int.TryParse;
This is also the reason why the type can't be inferred in the second example: int.TryParse is a method group and not of type TryParseMethod<int>.
I suggest, you use approach three and shorten the name of that extension class. I don't think there is any better way to do it.
Note that your code works if you first declare :
TryParseExtensions.TryParseMethod<int> tryParser = int.TryParse;
and then use tryParser where you used int.TryParse.
The problem is that the compiler doesn't know which overload of int.Parse you're speaking about. So it cannot completely infer it : are you speaking about TryParse(String, Int32) or TryParse(String, NumberStyles, IFormatProvider, Int32) ? The compiler can't guess and won't arbitrarily decide for you (fortunately !).
But your delegate type makes clear which overload you're interested in. That's why assigning tryParser is not a problem. You're not speaking anymore of a "method group" but of a well identified method signature inside this group of methods called int.TryParse.

Categories