How Optional Parameters work, why they can be dangerous, and why they work in .net 2/3 as well

One of the changes I really like in Visual Studio 2010 are optional parameters to method. Basically they allow you to specify a default value for each parameter and thus reduce the number of overloads to a method. Make sure to read to the end as there is a huge word of caution regarding optional parameters.

Instead of having this:

private static string SomeMethod(int value)
{
    return SomeMethod(value, "Was Empty");
}

private static string SomeMethod(int value, string data)
{
    return string.Format("{0}: {1}", value, data);
}

You can just have this:

// static because it's a console app, no extra magic
private static string OptionalMethod(int value, string data = "Was Empty")
{
    return string.Format("{0}: {1}", value, data);
}

The nice thing about this feature is that it also works with .net 2/3. Why? Because it is implemented like this:

private static string OptionalMethod(int value,
                          [Optional, DefaultParameterValue("Was Empty")] string data)
{
    return string.Format("{0}: {1}", value, data);
}

Looks like a normal method (the longest overload) with some attributes. Are those attributes the magic? No, it's much simpler.
If this is your calling code:

Console.WriteLine(OptionalMethod(1));
Console.WriteLine(OptionalMethod(2,"Test"));

Then this is how it looks in the compiled assembly:

Console.WriteLine(OptionalMethod(1, "Was Empty"));
Console.WriteLine(OptionalMethod(2, "Test"));

As you see, the compiler changes the method call to put in all optional parameters into the caller. This explains why this works with pre-.net 4 applications. However, this also explains the huge warning I want to give:

Changing the optional parameter value will not change the behavior of your callers!

Imagine you want to change the value to "No value specified". With the overload solution this is trivial:

private static string SomeMethod(int value)
{
    return SomeMethod(value, "No value specified");
}

Recompile your provider assembly and every consumer who uses that overload will get the new value. However, with optional parameters you have to re-compile each and every consumer assembly as well, so changing an optional parameter is a big, breaking change.

Does that mean that Optional Parameters are evil and should be avoided at all costs? Some people might think so, but I think they are useful for variables that almost never change. Think about a function like SendMail(string server, int port = 25).

However, I do object that ReSharper 5 offers the hint to introduce Optional Parameters too lightly:

Edit: I gave the ReSharper guys bad credit. If the method is declared as public, it does not offer that hint. Sorry guys for not double checking that! This then makes complete sense, as Optional Parameters are fine and safe for private/internal members.

I know too many people why blindly follow any advice that ReSharper give and that might see optional parameters as "Ohh, Shiny, no more Overloads!". Of course, you can argue that developers should know their stuff and deserve to fall hard on their face once they rolled it out as a big API and suddenly realize they have to recompile/redeploy dozens or hundreds of consumer assemblies because of a change. I am however not a fan of this type of developer elitism and would have preferred if ReSharper would not show that hint by default.

Just my 2 cents though.