I have been meaning to write something on this to remind me when I am tempted to use Optional Parameters, they are problematic, in a number of ways.
- Versioning
- Can not be used in expressions
- Can not pass null if the default is not null
Why and What
Optional Parameters were added to make COM and Automation interop easier. Both have great long method declarations with loads of parameters and declaring parameters as optional just makes it so much easier to call.
They reduce the need for so many overloads to methods and avoid the combinatorial effect on the number of overloads as you add parameters that you want to be optional.
A bit windy ...
class MyClass {
void AMethod(string thing1, string thing2){ ... }
void AMethod(string thing1){ ... }
void AMethod(string thing2){ ... }
}Better ...
class MyClass {
void AMethod(string thing1 = null, string thing2 = null){ ... }
}They have been supported by the CLR for ages, apparently since 1.0, but the C# implementation is not using the CLR 'truely' Optional Parameter, its a syntactic sugar.
When you make an optional parameter in your C#, the compiler adds the default value to the caller.
Given ...
class MyClass {
void AMethod(string thing = "One"){ ... }
}Then Calling ...
myClassInst.AMethod();
Actually compiles to in the calling assembly ...
myClassInst.AMethod("One");Versioning
The first problem
A result of the way the default value is compiled into the caller (see above). This means that if you were to change the default, the caller must be recompiled, and if the caller is another assembly which is not under your control - you can't do this.
Of course, changing your default would be a breaking change anyway.
The second problem
Adding overloads can easily change your Api.
This is "pretty subtle" as Phil says, take this example, version 1 ...
class MyClass {
public string AMethod (string thing1, string thing2 = "xxx") {
return "result";
}
}Adding an overload to version 2 ...
class MyClass {
public string AMethod(string thing1, string thing2 = "xxx") {
return "result";
}
public string AMethod(string thing2 = "xxx") {
return "different result";
}
}Now when you call version 1 using
Console.Write(myClassInst.AMethod("One"));> "result"
You get "result", but by adding the overload and calling the same on version 2 you get "different result"
Console.Write(myClassInst.AMethod("One"));> "different result"
The problem here is that the new overload of version 2 will hide the old overload and although the compiler will not complain when you do this, Resharper will give you a warning.
The Third problem
The compiler decides which overload to call using a set of rules, so where you have a call which matches the signature of more than one overload the rules determine which is called - but this is a different set of rules to those in VB, so you might break someone calling your component in C# from VB.
Cannot be used with Expressions
If you have a method with optional parameters, you cannot use that method in an expression unless you supply all arguments.
Given ...
class MyClass {
public string AMethod (string thing1 = "xxx") {
return "result";
}
}won't compile ...
var exp = (Expression<Action<MyClass>>) (o => o.AMethod());
will compile
var exp = (Expression<Action<MyClass>>)
(o => o.AMethod("xxx"));Your going to come across this at some point, and if you are providing an Api, the consumer is going to be restricted.
Can not pass null if the default is not null
There is not satisfactory way around this, given the following
class MyClass {
public string AMethod (string thing1 = "XXX") {
return "result";
}
}Both the following are equivalent, which means you pass null but you get the default, so you cannot pass null.
myClassInst.AMethod(); myClassInst.AMethod(null);
In JavaScript, for example, there is a type you can check for when the argument is not passed, namely 'undefined'. There is no such thing here.
Summing Up
I like the idea of optional arguments, because I don't like too many overloads.
But I don't like the idea that I will break my Api with one of these Gotchas
Code
VS2010 C# Solution: sandbox-optionalParameters.zip
References
http://msdn.microsoft.com/en-us/library/dd264739.aspx
http://lostechies.com/jimmybogard/2010/05/18/caveats-of-c-4-0-optional-parameters/
http://haacked.com/archive/2010/08/10/versioning-issues-with-optional-arguments.aspx
http://haacked.com/archive/2010/08/12/more-optional-versioning-fun.aspx
http://codebetter.com/2011/01/11/c-in-depth-optional-parameters-and-named-arguments-2/

