0

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?

Cui Pengfei 崔鹏飞
  • 8,017
  • 6
  • 46
  • 87
  • 1
    But you provide the value only if you don't want the default one.Please provide a Scala and a C# example side by side – quantdev Jun 10 '14 at 01:32
  • sorry, i was not being clear enough, I meant in the compiled result, in CIL and bytecode. In C# compiled CIL, the default value comes from the caller. In Scala compiled bytecode, the default value comes from the callee, which avoids the versioning issue described in the blog link – Cui Pengfei 崔鹏飞 Jun 10 '14 at 01:36
  • 2
    Why do you consider this error prone? If I am consuming your assembly with a default value of 1, I have written all of my unit tests and validated my functionality with that value. If the default is changed to 2 underneath me, my app could function incorrectly with that value. – John Koerner Jun 10 '14 at 01:48
  • like you said, your app could function incorrectly with that value, that's why i said it's error prone – Cui Pengfei 崔鹏飞 Jun 10 '14 at 06:01

1 Answers1

6

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.

Community
  • 1
  • 1
Jeroen Vannevel
  • 43,651
  • 22
  • 107
  • 170
  • I don't think Scala would have any problems with the corner cases. Scala does caller modification as well but it encodes a method call to a public compiler generated method in the callee's package. If C# had done this, there may have been some awkwardness interoperating with other .NET languages and tools that may show public members by default. Meanwhile, Scala default parameters are not accessible from Java (well, the compiler generated methods are public but there is no compiler support to insert the ugly calls for you). – Mike Zboray Jun 10 '14 at 02:55