4

Let's have a simple class, and main method:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace Rextester
{
public class Program
{
    public static void Main(string[] args)
    {
       bar bar = new bar();
        bar.foo("a");
    }
}

public class bar
{
    public void foo(String a, String b = "b")
    {
        Console.WriteLine("Foo1");            
    }       

}
}

This will write

Foo1

into the console.

Now, let's add an overload of the method into the class, using optional parameters:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace Rextester
{
public class Program
{
    public static void Main(string[] args)
    {
       bar bar = new bar();
        bar.foo("a");
    }
}

public class bar
{
    public void foo(String a, String b = "b")
    {
        Console.WriteLine("Foo1");            
    }

     public void foo(String a)
    {
        Console.WriteLine("Foo2");            
    }


}
}

This will write

Foo2

into the console.

I was expecting compile time error because I expect that foo(String a, String b = "b") represents both foo(String a) and foo(String a, String b) signature, because of the optional parameters. But I was wrong. Why is this allowed?

closed as off-topic by gnat, Dan Pichelman, Greg Burghardt, user22815, ChrisF Mar 15 '17 at 21:30

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Questions asking for assistance in explaining, writing or debugging code are off-topic here. These can be asked on Stack Overflow if they include the desired behavior, a specific problem or error, and the shortest code necessary to reproduce it in the question (see Minimal, Complete, and Verifiable Example)." – Community, ChrisF
If this question can be reworded to fit the rules in the help center, please edit the question.

  • 1
    Try searching on "Method Overloading", and I think you will find the answer(s) to your question. – Jon Raynor Mar 14 '17 at 17:44
  • 3
    stackoverflow.com/questions/39219180/… - Should provide answer. @Frustrated, thanks for the clarification. – Jon Raynor Mar 14 '17 at 17:59
  • 3
    @boucekv What kind of answer are you looking for to this question which is different from "because the spec says it is allowed"? – Philip Kendall Mar 14 '17 at 18:31
  • 1
    @boucekv - Then don't use optional parameters in this situation. :) The language designers give us the rules, we must abide by them when implementing code. – Jon Raynor Mar 14 '17 at 19:25
  • 2
    I remember how this came about. In the initial version of C# optional parameters were not supported at all. When people asked for them the designers answered "you don't need them, use overloads". It was a concious decision not to support optional parameters. In time support was added after all because of the pressure, people had grown used to having them in the old unmanaged languages. – Martin Maat Mar 14 '17 at 20:45
4

To start with an important quote from Eric Lippert

A lot of people seem to think that this:

void M(string x, bool y = false) { … whatever … }

is actually a syntactic sugar for the way you used to have to write this in C#, which is:

void M(string x) { M(x, false); }
void M(string x, bool y) { … whatever … }

But it is not. The syntactic sugar here is not on the declaration side, but rather on the call side. There is only one method; when you make a call that omits optional arguments, the compiler simply inserts the arguments at the call site. That is:

M(“hello”);

is rewritten as

M(“hello”, false);

I would recommend reading the whole series to really understand C#'s implementation of optional argument as call site rewriting. Basically your expectation

I expect that foo(String a, String b = "b") represents both foo(String a) and foo(String a, String b) signature

Is not how it works. Instead foo(String a, String b = "b") actually represents only foo(String a, String b). An example that Eric Lippert provides for why your intution would not work, is suppose that we had foo(String a = "a", String b = "b"). In this case one cannot nicely generate foo(String).

So that is why foo(String a, String b = "b") and foo(String a) can legitimately belong to the same class (because the optional parameter is filled in for callers rather than changing the declaration). Though it is a natural result of the implementation of optional parameters, it is clearly also error prone so there is still a question of why it is not disallowed.

I don't have a definitive answer here, and really only people involved in C#'s development could say, but to paraphrase Eric Lippert elsewhere, every feature in a language has an implementation cost; features that the designers don't feel are worth the cost just don't get implemented. In this case, making this probably incorrect code illegal is a feature with a definite cost and only marginal benefits (are people really mixing optional paramters and overrides in this way?) so it does not get implemented.

  • "are people really mixing optional paramters and overrides in this way?" yes, they are, and then like the op end up confused. – Andy Jun 18 '17 at 20:01
1

When you write any method call, the compiler will determine which method is called with which parameters. There will be a phase where the compiler determines all methods that could be called, then it complains if the number is zero, and it will try to determine the best one to call if there is more than one, complaining if it cannot decide.

In this case, the language has a rule that prefers a function with fewer parameters. I personally don't think this is a good rule, but Microsoft doesn't agree with my view. Had you overloaded as

public func foo (String a, String c = "c")

you would have got a warning.

Not the answer you're looking for? Browse other questions tagged or ask your own question.