18

While digging in my company codebase i found something that astounds me: pairs of functions that differ only in optional parameters, here's one example:

public static List<AvailableDay> Find(string mailboxCalendarId, string[] typeTrameCles, DateTime dateMin, bool hasPhNonUrgent, bool hasPhUrgence, bool hasPhUrgenceDuJour)
public static List<AvailableDay> Find(string mailboxCalendarId, string[] typeTrameCles, DateTime dateMin, bool hasPhNonUrgent, bool hasPhUrgence, bool hasPhUrgenceDuJour, int maxDaysResultCout = 1)

what I find very strange, is that the compiler is happy with them. What is the explanation for this? Am I missing something?

Ram
  • 3,092
  • 10
  • 40
  • 56
Souhaieb Besbes
  • 1,485
  • 17
  • 30
  • Perhaps you need to read up more on method overloads what is confusing about the 2 methods ? what makes the compiler not complain is that the 2 methods differ because the last parameter is `int maxDaysResultCout = 1` – MethodMan Dec 25 '15 at 15:21
  • 1
    I suppose technically they are different so the compiler won't mind? Of course the one without the optional parameter is redundant, but the compiler wouldn't really care about that. Although... Now you mention it, which one should be called if you make a method call without the optional parameter? Hmmm now I am confused too! – Ciara Dec 25 '15 at 15:22
  • 2
    Is your beef that it's not clear which is being called when invoking the method with the first signature? – Wai Ha Lee Dec 25 '15 at 15:24
  • 2
    @Ciara that's exacly my point – Souhaieb Besbes Dec 25 '15 at 15:26
  • 1
    All of this is just two clicks away in the [C# Language Specification](https://msdn.microsoft.com/nl-be/library/ms228593.aspx) and can be tested with a few lines of straightforward code. – Jeroen Vannevel Dec 25 '15 at 16:27
  • OT, but you may want to consider moving all those parameters into a single class, it's a bit messy as-is – BlueRaja - Danny Pflughoeft Dec 25 '15 at 21:49

2 Answers2

25

This is perfectly valid code. In your situation, however, the optional parameter is never used, because the compiler will always prefer the first overload when the method is invoked with six parameters.

From C# In Depth:

When faced with a choice between a method which requires the compiler to fill in optional parameter values and one which doesn't, if the methods are otherwise "tied" (i.e. normal argument conversion hasn't decided a winner), overload resolution will pick the one where the caller has specified all the arguments explicitly.

There may be situations when the compiler would pick the first overload over the second one because the more specific method is hidden. Here is a somewhat artificial example:

interface Foo {
    void Bar(int a, int b = 1);
}

class FooImpl : Foo {
    public void Bar(int a, int b) {
        Console.WriteLine("bar/2");
    }
    public void Bar(int a) {
        Console.WriteLine("bar/1");
    }
}

If you do this

Foo f1 = new FooImpl();
f1.Bar(1); // Here, Bar(int a, int b = 1) is the only choice

bar/2 gets printed, but if you do this

FooImpl f2 = new FooImpl();
f2.Bar(1); // Here Bar(int a) of the implementation wins

bar/1 gets printed (demo).

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • thanks for the example, but it confused because i don't have good understanding of the specifics of interfaces (i always use them in the most typical way): do both Bar methods in FooImpl implement the Bar in Foo? – Souhaieb Besbes Dec 25 '15 at 15:35
  • 1
    @SouhaiebBesbes No, only one of them implements `Bar` (i.e. the first one, with two parameters). The decision which method of the class implements what method of the interface is much more straightforward: the parameter types must match pairwise, regardless of the defaults that may be supplied with them. – Sergey Kalinichenko Dec 25 '15 at 15:38
  • ok it's all clear now, thanks – Souhaieb Besbes Dec 25 '15 at 15:40
  • @dasblinkenlight great answer and +1 for C# in Depth. I don't get though why f1.Bar(1) would use the optional parameter overload. Perhaps it was a typo? They are exactly the same! – jpgrassi Dec 25 '15 at 15:40
  • 1
    @jpgrassi because f1 is of type Foo, it has only the implementation with the optional parameters – Souhaieb Besbes Dec 25 '15 at 15:42
  • 1
    Oh man, I didn't see that! I was so focused on the overload part, totally ignored the interface and impl. – jpgrassi Dec 25 '15 at 15:43
7

First lets understand what are optional parameter

The optional parameter, is just a syntax sugar in C#.

If you have the following method that uses optional parameter:

public void DeleteFiles(string extension = "*.*")

The real signature of this method is

public void DeleteFiles(string extension)

The compiler does the trick here, when you use this method like that:

obj.DeleteFiles();

When compiler was doing her job, he got call to DeleteFiles without parameters, and he try to find it, but he couldn't so he will try to find and overload that uses a optional parameter that can match, this time he found, the DeleteFile(string), and now he does the trick.

In fact the compiled code will be this:

var extension = "*.*";
obj.DeleteFiles(extension);

So if you try to do this code:

public class A
{
    public void DeleteFiles(string extension = "*.*")
    {
    }

    public void DeleteFiles(string extension2)
    {
    }
}

The compiler will give the following error message:

Error CS0111: Type 'A' already defines a member called 'DeleteFiles' with the same parameter types

Now lets your question

Now we have this class

public class A
{
    public void DeleteFiles(string folderPath)
    {
    }

    public void DeleteFiles(string folderPath, string extension = "*.*")
    {
    }
}

The real code in this case is

public class A
{
    public void DeleteFiles(string folderPath)
    {
    }

    public void DeleteFiles(string folderPath, string extension)
    {
    }
}

Then you have this code:

aInstance.DeleteFiles("path")

The compiler will look if there is a DeleteFiles method that receive one parameter. He will find it.

Conclusion

So in this case, the optional parameter feature, will never be used, because there is a perfect method signature that makes compiler never try to find a other signature that used optional parameter.

Alberto Monteiro
  • 5,989
  • 2
  • 28
  • 40
  • Ciara explained what's confusing me : 'which one should be called if you make a method call without the optional parameter?', your answer doesn't clarify that. thanks to dasblinkenlight we get the answer that the compiler gives priority to the method with the exact signature – Souhaieb Besbes Dec 25 '15 at 15:28
  • i think you misunderstood the question, the two methods don't have the same number of parameters – Souhaieb Besbes Dec 25 '15 at 15:38
  • @SouhaiebBesbes I didnt, I explained what optional parameters are, and how compiler handle them. They are just a syntax sugar, and compiler always try to get the exact parameter list first, if there is not, he try the method with optional parameters – Alberto Monteiro Dec 25 '15 at 15:41
  • i really can't read that in your answer – Souhaieb Besbes Dec 25 '15 at 15:43
  • thanks it now answers the question with a clear example – Souhaieb Besbes Dec 25 '15 at 15:57
  • @SouhaiebBesbes You are welcome, I am happy that I could help you! – Alberto Monteiro Dec 25 '15 at 15:58