How does C# choose with ambiguity and params - c#

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

Related

Why could C# overload two methods with the same params as long as one of them has default param?

I recently noticed that C# compiler allows methods overloads like the following:
public static string foo(string a, bool x = false)
{
return "a";
}
public static string foo(string a)
{
return "b";
}
As far as I tested, it always returns "b" as long as the second param is not given, which makes sense. However, I think the compiler really should not allow this type of overloading. May I ask the reason why this feature is designed like this rather than giving an error by compiler?
While questions like this are fundamentally impossible to answer, since it is impossible to guess the language designers intentions, I might make a guess.
Optional arguments are handled by transforming the code to inject the argument to the call site. So
public static void Test(int a = 42){...}
...
Test();
would be transformed to to
public static void Test(int a){...}
...
Test(42);
by the compiler. From this point on the regular overload resolution can run without conflicts. Why was it designed this way? I have no idea, but common reasons for non intuitive features is backward compatibility or language compatibility.
For this reason it is important to be very careful using optional arguments in public APIs. Since the user of the library will use the default value from the version of the API it was compiled against. Not the version it is running against.
I can't speak to why this is part of the design so much as simply explain why you see which overload is favored in your testing.
If you look at the reference documentation, you'll note the following three bullets to describe overload resolution:
A method, indexer, or constructor is a candidate for execution if each of its parameters either is optional or corresponds, by name or by position, to a single argument in the calling statement, and that argument can be converted to the type of the parameter.
If more than one candidate is found, overload resolution rules for preferred conversions are applied to the arguments that are explicitly specified. Omitted arguments for optional parameters are ignored.
If two candidates are judged to be equally good, preference goes to a candidate that doesn't have optional parameters for which arguments were omitted in the call. Overload resolution generally prefers candidates that have fewer parameters.
I would assert that in your test, bullet #3 is most applicable to your observations - because you omit the second argument and either method is equally good, resolution favors your second method and you see "b" returned.

Strange C# compiler behavior when choosing overload that looks like a bug/missing feature

I have recently found an interesting behavior of C# compiler. Imagine an interface like this:
public interface ILogger
{
void Info(string operation, string details = null);
void Info(string operation, object details = null);
}
Now if we do
logger.Info("Create")
The compiler will complain that he does not know which overload to chose (Ambiguous invocation...). Seems logical, but when you try to do this:
logger.Info("Create", null)
It will suddenly have no troubles figuring out that null is a string. Moreover it seems that the behavior of finding the right overload has changed with time and I had found a bug in an old code that worked before and stopped working because compiler decided to use another overload.
So I am really wondering why does C# not generate the same error in the second case as it does in the first. Seems very logical to do this, but instead it tries and resolves it to random overload.
P.S. I don't think that it's good to provide such ambiguous interfaces and do not recommend that, but legacy is legacy and has to be maintained :)
There was a breaking change introduced in C# 6 that made the overload resolution better. Here it is with the list of features:
Improved overload resolution
There are a number of small improvements to overload resolution, which will likely result in more things just working the way you’d expect them to. The improvements all relate to “betterness” – the way the compiler decides which of two overloads is better for a given argument.
One place where you might notice this (or rather stop noticing a problem!) is when choosing between overloads taking nullable value types. Another is when passing method groups (as opposed to lambdas) to overloads expecting delegates. The details aren’t worth expanding on here – just wanted to let you know!
but instead it tries and resolves it to random overload.
No, C# doesn't pick overloads randomly, that case is the ambiguous call error. C# picks the better method. Refer to section 7.5.3.2 Better function member in the C# specs:
7.5.3.2 Better function member
Otherwise, if MP has more specific parameter types than MQ, then MP is better than MQ. Let {R1, R2, …, RN} and {S1, S2, …, SN} represent the uninstantiated and unexpanded parameter types of MP and MQ. MP’s parameter types are more specific than MQ’s if, for each parameter, RX is not less specific than SX, and, for at least one parameter, RX is more specific than SX:
Given that string is more specific than object and there is an implicit cast between null and string, then the mystery is solved.

Static method and extension method with same name

I created extension method:
public static class XDecimal
{
public static decimal Floor(
this decimal value,
int precision)
{
decimal step = (decimal)Math.Pow(10, precision);
return decimal.Floor(step * value) / step;
}
}
Now I try to use it:
(10.1234m).Floor(2)
But compiler says Member 'decimal.Floor(decimal)' cannot be accessed with an instance reference; qualify it with a type name instead. I understand there is static decimal.Floor(decimal) method. But it has different signature. Why compiler is unable to choose correct method?
You have two good and correct answers here, but I understand that answers which simply quote the specification are not always that illuminating. Let me add some additional details.
You probably have a mental model of overload resolution that goes like this:
Put all the possible methods in a big bucket -- extension methods, static methods, instance methods, etc.
If there are methods that would be an error to use, eliminate them from the bucket.
Of the remaining methods, choose the unique one that has the best match of argument expressions to parameter types.
Though this is many people's mental model of overload resolution, regrettably it is subtly wrong.
The real model -- and I will ignore generic type inference issues here -- is as follows:
Put all the instance and static methods in a bucket. Virtual overrides are not counted as instance methods.
Eliminate the methods that are inapplicable because the arguments do not match the parameters.
At this point we either have methods in the bucket or we do not. If we have any methods in the bucket at all then extension methods are not checked. This is the important bit right here. The model is not "if normal overload resolution produced an error then we check extension methods". The model is "if normal overload resolution produced no applicable methods whatsoever then we check extension methods".
If there are methods in the bucket then there is some more elimination of base class methods, and finally the best method is chosen based on how well the arguments match the parameters.
If this happens to pick a static method then C# will assume that you meant to use the type name and used an instance by mistake, not that you wish to search for an extension method. Overload resolution has already determined that there is an instance or static method whose parameters match the arguments you gave, and it is going to either pick one of them or give an error; it's not going to say "oh, you probably meant to call this wacky extension method that just happens to be in scope".
I understand that this is vexing from your perspective. You clearly wish the model to be "if overload resolution produces an error, fall back to extension methods". In your example that would be useful, but this behaviour produces bad outcomes in other scenarios. For example, suppose you have something like
mystring.Join(foo, bar);
The error given here is that it should be string.Join. It would be bizarre if the C# compiler said "oh, string.Join is static. The user probably meant to use the extension method that does joins on sequences of characters, let me try that..." and then you got an error message saying that the sequence join operator -- which has nothing whatsoever to do with your code here -- doesn't have the right arguments.
Or worse, if by some miracle you did give it arguments that worked but intended the static method to be called, then your code would be broken in a very bizarre and hard-to-debug way.
Extension methods were added very late in the game and the rules for looking them up make them deliberately prefer giving errors to magically working. This is a safety system to ensure that extension methods are not bound by accident.
The process of deciding on which method to call has lots of small details described in the C# language specification. The key point applicable to your scenario is that extension methods are considered for invocation only when the compiler cannot find a method to call among the methods of the receiving type itself (i.e. the decimal).
Here is the relevant portion of the specification:
The set of candidate methods for the method invocation is constructed. For each method F associated with the method group M:
If F is non-generic, F is a candidate when:
M has no type argument list, and
F is applicable with respect to A (§7.5.3.1).
According to the above, double.Floor(decimal) is a valid candidate.
If the resulting set of candidate methods is empty, then further processing along the following steps are abandoned, and instead an attempt is made to process the invocation as an extension method invocation (§7.6.5.2). If this fails, then no applicable methods exist, and a binding-time error occurs.
In your case the set of candidate methods is not empty, so extension methods are not considered.
The signature of decimal.Floor is
public static Decimal Floor(Decimal d);
I'm no specialist in type inference, but I guess since there is a implicit conversion from int to Decimal the compiler chooses this as the best fitting method.
If you change your signature to
public static decimal Floor(
this decimal value,
double precision)
and call it like
(10.1234m).Floor(2d)
it works. But of course a double as precision is somewhat strange.
EDIT: A quote from Eric Lippert on the alogrithm:
Any method of the receiving type is closer than any extension method.
Floor is a method of the "receiving type" (Decimal). On the why the C# developers implemented it like this I can make no statement.

C# Methods differ only by optional parameters

I have found this topic, but it's VB...and they get an error:
vb issue
Here are my method signatures. Notice one has a different return type.
public static bool PopulateRunWithSimpleValueByFieldIdSync(string fieldValue, string fieldId, IViewModel myself, int index)
VS
public static void PopulateRunWithSimpleValueByFieldIdSync(string fieldValue, string fieldId, IViewModel myself, int index = 0, PopulateDoneCallback populateDone = null)
The actual call I was making:
PopulateRunWithSimpleValueByFieldIdSync(date, dtx.DateField, saver, index);
The compiler decided to pick the first method, and not give me an error. Once the first method was removed (it was unused code), it started calling the second method.
Is there an option somewhere to treat this as an error?
You're going to need to use some form of 3rd party code analysis if you want this to be flagged at compile time, since the C# language specs define the current behavior as what should happen.
According to the C# language guide (emphasis mine),
Use of named and optional arguments affects overload resolution in the following ways:
...
If two candidates are judged to be equally good, preference goes to a candidate that does not have optional parameters for which arguments were omitted in the call. This is a consequence of a general preference in overload resolution for candidates that have fewer parameters.
You can use a third party analysis tool to flag this as an error or to use Visual Studio's built in static code analysis too with a custom rule that you implement.
This is per design, according to the specs
Use of named and optional arguments affects overload resolution in the
following ways:
A method, indexer, or constructor is a candidate for execution if each of its parameters either is optional or corresponds, by name or
by position, to a single argument in the calling statement, and that
argument can be converted to the type of the parameter.
If more than one candidate is found, overload resolution rules for preferred conversions are applied to the arguments that are explicitly
specified. Omitted arguments for optional parameters are ignored.
If two candidates are judged to be equally good, preference goes to a candidate that does not have optional parameters for which arguments
were omitted in the call. This is a consequence of a general
preference in overload resolution for candidates that have fewer
parameters.
So, no - you can't.

C# generics -- why do lambdas work, when simple methods don't?

I'm having trouble understanding why the C# compiler can infer types for
Array.ConvertAll(new int[1], i => Convert.ToDouble(i));
but not for
Array.ConvertAll(new int[1], Convert.ToDouble);
when it would seem that the former would be a more complicated deduction than the latter.
Could someone please explain why this happens?
This issue is pretty well covered in this (archived) blog post: http://blogs.msdn.com/b/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not-work-on-member-groups.aspx
In summary as I understand it (should the link ever vanish); this was a conscious design decision in C# 3.0, in that it was not appropriate to perform type inference on Method Groups (your second example).
I guess quite a few folks didn't like that, so the issue was resolved for C# 4.0 (as of Visual Studio 2010);
"In C# 4.0, return type inference works on method group arguments when the method group can be associated unambiguously with a completely fixed set of argument types deduced from the delegate. Once the argument types associated with the method group are known, then overload resolution can determine unambiguously which method in the method group is the one associated with the delegate formal parameter; we can then make a return type inference from the specific method to the delegate return type."

Categories