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.

 

 

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