Reputation: 265
Please bear with me, this is not (quite!) a duplicate of any of these SO answers:
When trying to "influence" what overload the compiler will choose given conflicts arising from optional parameters, answers in the above posts reference the C# Programming Guide, which indicates the overload resolution (OR) heuristics at play here:
If two candidates are judged to be equally good, preference goes to a candidate that does not have optional parameters for which arguments were omitted in the call.
Fair enough. My question is, why doesn't (or why can't) the Obsolete attribute (or some other markup) influence the OR decision on judging two candidates to be equally good? For example, consider the following overloads:
[Obsolete(“This method is deprecated.”)]
[EditorBrowsable(EditorBrowsableState.Never)]]
bool foo() { return true; }
bool foo(bool optional = false) { return optional; }
It seems OR should not judge these overloads to be equally good--the non-deprecated overload with an optional parameter should win. If this were the case in this over-simplified example, code previously compiled for foo() would be backwards compatible and happily continue to return true. Future code compiled for this library could also call foo(), but that resolved overload would return false.
Is this a valuable/possible feature we are missing from the language? Or is there any other way to make this wish of mine work? Thanks for any insights,
-Mike
Upvotes: 2
Views: 520
Reputation: 4994
It's an interesting question. Still, I prefer it the way it is for the following reasons:
Simplicity
OR depends on method signature compiled to module and it is intuitive at that. Depending on any attributes would change the dependency scope to a wider "thing" and start snowballing - should you consider maybe another attribute? Or attributes on arguments, etc..
Change management
Method signatures & OR are different concern than the deprecation marker attribute. The latter is metadata and if it started to affect OR from one point on, then it would possibly break many existing applications. Especially libraries where deprecation cycle is longer for a reason.
I would be very annoyed if a functionally tested code started to behave different after a soft decision that a certain part of code will be phased out in "undetermined future".
Upvotes: 0
Reputation: 21855
All in all having code like this ...
[Obsolete(“This method is deprecated.”)]
bool foo() { return true; }
bool foo(bool optional = false) { return optional; }
stinks. The compiler will apply an algorithm to select the right method when you call foo()
but any developer looking at the code will need to know (and to apply) that algorithm to understand what the code does so maintainability of the code will decrease a lot.
Simply remove the optional in this case as it hurts more than anything else.
Upvotes: 0
Reputation: 149020
Overload resolution is a very tricky thing to get right, and language designers think long and hard about exactly what the rules should be. The more different considerations and special cases you add, the likely language users are to run into obscure gotchas where it doesn't quite work the way they'd expect. I don't believe adding this new condition to overload resolution would be a valuable addition to the language.
If OR did prefer the method without the ObsoluteAttribute
, then the only way to invoke the obsolete method without reflection would be something like this:
((Action)obj.foo)();
And if this were a generic method, there would be no way to call it with an anonymous type parameter. This would definitely be surprising behavior (at least to me).
The ObsoleteAttribute
(declared with IsError = false
) is a way for you to provide a hint for your consumers to update their code without completely removing the previous capabilities. Typically you want to do this if you plan to remove the feature in a future version. If you want to prohibit them from calling this method entirely, you can either:
IsError = true
with [Obsolete("This method is deprecated.", true)]
so that if the code is re-compiled, it generates an error rather than a warning. It could still be called via reflection.Upvotes: 1