For instance, I have the following code:
Module Module1
Sub Main()
Say()
End Sub
Sub Say(Optional ByVal what As String = "Hello World!")
Console.WriteLine(what)
End Sub
End Module
The compiled version is a bit more interesting (converted from IL to VB):
Module Module1
<STAThread> _
Public Shared Sub Main()
Module1.Say("Hello World!")
End Sub
Public Shared Sub Say(ByVal Optional what As String = "Hello World!")
Console.WriteLine(what)
End Sub
End Module
Notice in the compiled version, that default value ("Hello World!") is supplied as a parameter to [Say]. Not a problem unless an assembly you haven't/can't deploy calls a method you just added an optional parameter for. Lets say we had an older version of my program where [Say] didn't take any parameters and just printed "Hello World!" to the screen. I decide later to get a little more modular and move [Say] to its own assembly. I update my program to use it the new method and everything is cool. Time goes by and I need a more generic version of [Say] so I add the [Optional what As String] parameter and deploy the modified assembly.
And then not too long later, I start getting informed from every person who happens to be using my assembly and calling [Say] that their applications are now blowing up.
Because the dependent applications weren't compiled with the new optional parameter in mind, they're trying to call a parameterless version of [Say] which, in reality, doesn't exist. Therefore, care should be taken when using optional parameters to maintain compatibility with assemblies that you can't/don't want to have to redeploy. In those situations, an overloaded method would be the best way to go.
I guess the beauty of optional parameters, as everything else, is only skin deep.