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