Default arguments and versioning

I was recently asked about why the
CLS (and the Design Guidelines) discourages default arguments. So I added this annotation to the Design
Guidelines document. I believe it
is the same reason why C# (rightfully) left it out of the
language."urn:schemas-microsoft-com:office:office" />

The issue with default arguments and
versioning is that once you define a default argument you can never change its
value. Consider the following
method (in VB as C# does not support default arguments; the basic issue exists
in C++ as well).

   Public
Shared Function ComputeTotal(ByVal subtotal As Double,

                                    
Optional ByVal salesTaxPrecent As Double = 8.8) As
Double

       
ComputeTotal = subtotal + subtotal * salesTaxPrecent /
100

    End
Function

Call
site:

Foo.ComputeTotal(100)

Looking
at the IL disassembly for this call is instructive in showing what is going
on:
   IL_0001: ldc.r8
100.

  IL_000a: ldc.r8
8.8000000000000007

  IL_0013: call float64
ConsoleApplication5.Foo::ComputeTotal(float64,

                                                                    
float64)

Notice
in line 000a the VB compiler generated the IL instruction to load the literal
8.8. This is burned into the call
site. If we change the definitions
of the default value for salesTaxPrecent to 7.8% and do not recompile the
calling code (as is common when working with large frameworks) 8.8 will continue
to be passed as the default value.
This can be a very nasty bug to track down!

Using
method overloading encapsulates the default value so that it can be changed in a
predictable way.

   Public Shared Function
ComputeTotal(ByVal subtotal As Double, ByVal salesTaxPrecent As
Double)

                                      
As Double

       
ComputeTotal = subtotal + subtotal * salesTaxPrecent /
100

    End
Function

    Public Shared Function
ComputeTotal(ByVal subtotal As Double) As Double

       
ComputeTotal = ComputeTotal(subtotal, 8.8)

    End
Function