Search code examples
c#scalalanguage-designoptional-parametersdefault-parameters

Why does C# make the caller provide the actual parameter value for a method that has an optional parameter?


The last section of this blog explains the what: http://lostechies.com/jimmybogard/2010/05/18/caveats-of-c-4-0-optional-parameters/

But I am still wondering about the why.

I recently came across the default parameter of Scala.

In Scala it's the callee who provides the actual value for a parameter that has a default value. So all the callers don't have to be recompiled to use an updated default parameter value.

If Scala can do it, I guess C# could have done it too.

So, why? Why did they design it to be error prone?

Edit:

Error prone might be too strong a word, so my question is more like this:

Why is it designed in a way that versioning of the default parameter could not affect the callers?


Solution

  • From the words of Eric Lippert himself:

    That is, they believe that the default value is somehow “baked in” to the callee.

    In fact, the default value is baked in to the caller; the code on the callee side is untouched and the caller becomes

    M("{0}", false);

    A consequence of this fact is that if you change the default value of a library method without recompiling the callers of that library, the callers don’t change their behaviour just because the default changed. If you ship a new version of method M that changes the default to true it doesn’t matter to those callers. Until a caller of M with one argument is recompiled it will always pass false.

    That could be a good thing. Changing a default from false to true is a breaking change, and one could argue that existing callers should be insulated from that breaking change. [emphasis mine]

    This is a fairly serious versioning issue, and one of the main reasons why we pushed back for so long on adding default arguments to C#. The lesson here is to think carefully about the scenario with the long term in mind. If you suspect that you will be changing a default value and you want the callers to pick up the change without recompilation, don’t use a default value in the argument list; make two overloads, where the one with fewer parameters calls the other.

    Source: Optional argument corner cases, part four (full series)

    As to why this is different in Scala: perhaps there are technical constraints in C# that don't exist there. If you look through the 4 posts on optional arguments you'll notice that they have many cornercases to keep in mind.

    If it isn't a technical constraint it might very well have been a managerial one. As has been often indicated:

    Here's how we designed C# 4.

    First we made a list of every possible feature we could think of adding to the language.

    Then we bucketed the features into "this is bad, we must never do it", "this is awesome, we have to do it", and "this is good but let's not do it this time".

    Then we looked at how much budget we had to design, implement, test, document, ship and maintain the "gotta have" features and discovered that we were 100% over budget.

    So we moved a bunch of stuff from the "gotta have" bucket to the "nice to have" bucket.

    Every minute we spend designing, implementing, testing, documenting or maintaining nice feature X is a minute we can't spend on awesome features A, B, C, D, E, F and G. We have to ruthlessly prioritize so that we only do the best possible features. Indexed properties would be nice, but nice isn't anywhere even close to good enough to actually get implemented.