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.

  1. Versioning
  2. Can not be used in expressions
  3. 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/

http://www.grumpydev.com/2010/04/19/optional-parameters-in-c4-c3-and-vb-net-with-a-side-order-of-il-quirks/

For instance

public int Add(int a = 0, int b = 1, int c = 2)

{

return a + b + c;

}

public double Add(int a, double b=1, double c = 2)

{

return a + b + c+100;

}

Add(1);

The above method call throw the below compile time error.

The call is ambiguous between the following methods or properties:


Post a Note

(required)

(required never shown)

On Twitter Follow MrAntix on Twitter

a minute ago
Appleforyoumac
Two factor authentications happen on Windows Azure http://t.co/uOb0Vithxx

3 minutes ago
mopperkop
RT @EricLigman: How you claimed your #FREE #Microsoft eBooks? http://t.co/57dCbiwpyn I'm trying to give away 1,000,000 of them. #MSPartner

4 minutes ago
shortedfuse
RT @maryjofoley: ICYMI: Tons of free MS ebooks on all kinds of techs of interest to IT pros/devs, courtesy of @EricLigman http://t.co/k1RiV…

10 minutes ago
Jbarsodi
Huge collection of Free Microsoft eBooks. No Lync or Exchange :( , but some SharePoint and Windows Server. http://t.co/Oj7VU103cI

13 minutes ago
TechMike2kX
RT @CoditCompany: all our blog posts on windows azure biztalk services can be found here : http://t.co/XegFxB19hj #msbts #wabs