views:

221

answers:

4

I have two overloaded methods, one with an optional parameter.

void foo(string a)  { }  
void foo(string a, int b = 0) { }  

now I call:

 foo("abc");

interestingly the first overload is called. why not the second overload with optional value set to zero?

To be honest, I would have expect the compiler to bring an error, at least a warning to avoid unintentional execution of the wrong method.

What's the reason for this behaviour? Why did the C# team define it that way?
Thanks for your opinions!

+4  A: 

An overload which doesn't require any optional parameters to be filled in automatically is preferred to one which does. However, there's no such preference between filling in one argument automatically and filling in more than one - so for example, this will cause a compile-time error:

void Foo(int x, int y = 0, int z = 0) {}
void Foo(int x, int y = 0) {}
...
Foo(5);

Note that Foo(5, 5) would be resolved to the second method, because then it doesn't require any optional parameters to be automatically filled in.

From section 7.5.3.2 of the C# 4 spec:

Otherwise if all parameters of MP have a corresponding argument whereas default arguments need to be substituted for at least one optional parameter in MQ then MP is better than MQ.

I think in most cases this is the behaviour most people would expect, to be honest. It gets weird when you introduce base class methods into the mix, but that's always been the case.

Jon Skeet
Thanks for your answer. Still one question remains:WHY did they define it that way?Is there a scenerio where the overload with the optional parameter makes sense? It will never be called with the default value, right?But it can lead to unwanted mistakes. I still think the compliler should give at least a warning.And there are other examples where the developer has to tell the compiler explicitly that he is aware of what he is doing. For example if a parameter in a method is declared as ref, I need to explicitly use the ref keyword in the method call too; otherwise it won't compile.
Thomas
@Thomas: I'm afraid I don't have any answers for the rationale - although Eric Lippert might. I wouldn't want you to have to add any *more* baggage to the calling code though - after all, the reason for default parameters is precisely to *reduce* the amount of code you need.
Jon Skeet
+3  A: 

From MSDN:

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.

Dean Harding
+1  A: 

Just imagine if it were the opposite. You had an application. It had a method:

void foo(string a)  { }   

Everyting worked fine. Now, you want to add one more overload with an optional parameter:

void foo(string a, int b = 0) { }  

Boom! All method calls go to the new method. Whenever you want it or not. Adding a method overload might cause wrong method calls all over the application.

From my perspective, in this case you'd have much more opporunities to break your (or someone else's) code.

Also, OptionalAttribute was ignored in C# until version 4.0, but you could use it. And some people did use it in C# code to support certain interoperability scenarios with other languages, such as Visual Basic, or for COM interop. Now C# uses it for optional parameters. Adding warnings/errors may introduce a breaking change for those applications.

There might be some other reasons, but this is just what comes to my mind first.

Alexandra Rusina
A: 

The strangest is that if the first method was overriding virtual method from base class, then the second method will be invoked instead of first one. There is bug submitted to Microsoft Connect (Unintuitive virtual method resolution with optional parameters)

Craccoon