Closer is better

Overload resolution is of course the process of taking a bunch of things with the same name and figuring out which of them the user meant. Different languages use different heuristics to try to figure this out. A “heuristic” is just a fancy word for a guess, and I’ve often said that one of the design characteristics of C# is that it is not a “guess what the user meant” kind of language. So if C# is going to make guesses, at least the process by which it does so should be easily explainable to users.

The aspect of overload resolution in C# I want to talk about today is really the fundamental rule by which one potential overload is judged to be better than another for a given call site: closer is always better than farther away. There are a number of ways to characterize “closeness” in C#. Let’s start with the closest and move our way out:

  • A method first declared in a derived class is closer than a method first declared in a base class.
  • A method in a nested class is closer than a method in a containing class.
  • Any method of the receiving type is closer than any extension method.
  • An extension method found in a class in a nested namespace is closer than an extension method found in a class in an outer namespace.
  • An extension method found in a class in the current namespace is closer than an extension method found in a class in a namespace mentioned by a using directive.
  • An extension method found in a class in a namespace mentioned in a using directive where the directive is in a nested namespace is closer than an extension method found in a class in a namespace mentioned in a using directive where the directive is in an outer namespace.

The overload resolution algorithm can be thought of as making a list of every method of a given name, ordering them by closeness using the above metrics, discarding all methods that are farther away than the closest method, and then doing additional tiebreakers on the methods that remain. Of course that is not actually what the compiler does; if for example any instance method can be found then searching for extension methods is elided.

Once you realize that this characterization of “closeness” is the first and deepest cut that the overload resolution algorithm makes, answers to other questions become clear:

And with that, I’m done for 2013. This was an interesting and eventful year for me. New job, new blog location, new office, new product. I’m looking forward to things being a little more routine in 2014. Thanks all for your always-interesting comments and questions. See you for more fabulous adventures next year!

 

7 thoughts on “Closer is better

  1. Hi Eric,

    Great post! Found it in your SO answer on the same subject (http://stackoverflow.com/a/1451184). I noticed one of the comments in that post asked about hiding a class method with an extension method, but you explained that class hierarchy always wins over an extension method.

    But what about hiding a class method with another overload with default parameters? I know OR heuristics specify that “preference goes to a candidate that does not have optional parameters for which arguments were omitted in the call.” Do you know why the Obsolete attribute doesn’t seem to affect the OR decision on judging two candidates to be equally good?

    For example, it seems OR could judge the overload with an optional parameter to be better given the following markup on the default overload:

    [Obsolete(“This method is deprecated.”)]
    [EditorBrowsable(EditorBrowsableState.Never)]]
    bool foo() { return true; }

    bool foo(bool optional = false) { return optional; }

    I would expect false to be returned from a call to foo() above. Or do you know any way to make that work? Thanks for your insight,
    -Mike

  2. Pingback: 如何覆盖现有的扩展方法 – CodingBlog

  3. Pingback: C# method override resolution weirdness | Developer FAQs

  4. Pingback: Почему вызывается перегруженный метод? - c# c#-faq - Вопросы и ответы по программированию

  5. Pingback: How to override an existing extension method – Row Coding

  6. Pingback: Overriding an existing extension method - Row Coding

Leave a comment