Core5: Overloading on optional parameters

[This post is part of a series, "wish-list for future versions of VB"]

IDEA: Overloading on optional parameters. Allow you to have overrides which differ only in their optional parameters. The rules for "overloaded method resolution" would have to be augmented with a new tie-breaker rule, e.g. like C# "... otherwise, if one overload had at least one missing optional argument, and another overload had no missing optional arguments, then prefer the second overload".

SCENARIO: You wrote a library which initially looked like this:,
    Sub fopen(fn As String, Optional mode As OpenMode = OpenMode.Input)

But now you want to release a second version of your library which takes two parameters,

    Sub fopen(fn As String, Optional mode As OpenMode = OpenMode.Input,

              Optional password As String = "")

You want to do this in such a way that you don't break binary compatibility (i.e. applications that had been compiled against the old library should continue to run against the new one without recompiling). You also don't want to break source compatibility (i.e. if an application compiled against the old library, it should recompile against the new library too).

This scenario requires "overloading on optional parameters" to work.

 

This scenario isn't as clear-cut as you'd think. For a start, CLS guidelines say to "NEVER expose optional parameters in your frameworks". Microsoft isn't going to be exposing optional parameters in its frameworks. What we use instead is many different overloads of a method.

On the other hand, multiple overloads aren't nice. When you're calling a method, the intellisense is nicer if there's only a single overload where it can show all the optional parameters. And multiple overloads are just bloat. We recognize the advantages of optional parameters, and think that the CLS guidelines are too strict for users, so C# 4.0 users won't get a warning even when they use optionals in a class marked [CLSCompliant(true)].

In the scenario, though, to preserve binary compatibility, we've still had to keep both overloads, and you still see both candidates in the intellisense when you invoke the method. What we'd like is to <Obsolete> the old version of "fopen" so as to guide users onto the new version of "fopen", and to change intellisense so that <Obsolete> members don't show up.

But that doesn't work! Any user who writes fopen("file.txt") will end up picking the <Obsolete> overload. So to make this work perfectly you'd need overload resolution to prefer candidates overloads without <Obsolete>. But now we're getting onto shakey ground... it would be awful if a decorative attribute like <Obsolete> had real semantic effect, changing the behavior of your code (i.e. changing which overloads get picked). Also it would break backwards compatibility.

We also have to consider that the rules for overloaded method resolution are already extraordinarily complicated (and have evolved into this so as not to break backwards compatibility as new features were introduced). Inevitably, if we add tie-breaker rules to them, we'll get unexpected behaviors in some corner case or other.

In the end, I don't see a good answer here that solves every problem.

Thanks to Bill McCarthy for raising these points and spelling out the issues.

 

 

Provisional evaluation from the VB team: This is a decent idea, one that we should consider against the other decent ideas. Even if we can't solve every problem, this change would at least provide some benefit (and bring parity with C#).