Although I greatly respect the opinons of my fellow Microsoft employees (and most other people, for that matter), there are times when we have honest differences of opinions. A recent blog entry by Brad on default parameters is a good example.
I understand the versioning argument that he and the C# team make about default arguments, but I just don’t buy it. I think that not having (or not ever using) default arguments because of versioning is throwing out the baby with the bathwater. Brad gives an example of a VB function with a default argument:
Function ComputeTotal(ByVal subTotal As Double, Optional ByVal salesTax As Double = 8.8) As Double
Return subTotal + subTotal * salesTax / 100
End Function
He suggests that the following would be better:
Function ComputeTotal(ByVal subTotal As Double, ByVal salesTax As Double) As Double
Return subTotal + subTotal * salesTax / 100
End Function
Function ComputeTotal(ByVal subTotal As Double) As Double
Return ComputeTotal(subTotal, 8.8)
End Function
He feels the latter example is better because you can change the default value of salesTax and automatically have all clients compiled against the method pick up the change. Which is true. But I have to ask: what class library designer in their right mind would change the default value in the first place?
One of the major areas of concern for class library designers inside of Microsoft is compatibility, and one of the cardinal rules of compatibility is that you don’t make this kind of behavioral change. Why not? Because you’re likely to break people who depend, rightly or wrongly, on the default behavior that you introduced. (If you have any doubts about this, go talk to Raymond.)
In the given example, yes, the state may have changed its sales tax and so the calculation function may need to change. But just changing the default may cause serious issues. What if your application needs to calculate sales tax for sales that occured before the sales tax rate changed? Yes, you should have explicitly stated the sales tax you want to use, but it’s just as likely you used the default because: a) it’s easier and b) at the time you wrote your code, you got the expected result. As a result, when the default changes you’ll end up willy-nilly calculating the sales tax with the wrong rate! I would argue that in this situation the problem has less to do with default arguments or overloading than it does with bad API design.
My point is that whether you use default arguments or overloading, it’s extremely unlikely that you’re ever going to be able to change default values once you’ve published an API. That is, unless the API is completely internal to your application. In which case, the versioning “problem” with default arguments doesn’t apply! So in this case, I think the prohibition against default arguments is worrying about what happens in a situation that shouldn’t occur in the first place.
I will hasten to add that this doesn’t mean that I don’t think that overloading isn’t a good thing or that default arguments can be abused. (Anyone with any doubt on that last point only has to look no further than the Office object model.) In practice, I think that proper API design trends in favor of overloading simply because it encourages simpler API calls and reduces the need for things like named arguments. But there are definitely places where default arguments can be used to avoid adding superfluous overloads with very little overhead.