bearxy39
bearxy39

Reputation: 51

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?

Upvotes: 4

Views: 751

Answers (2)

Whit Waldo
Whit Waldo

Reputation: 5207

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.

Upvotes: 1

JonasH
JonasH

Reputation: 36341

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.

Upvotes: 1

Related Questions