Color Color


Pop quiz: What does the following code do when compiled and run?

class C
{
    public static void M(string x)
    {
        System.Console.WriteLine(“static M(string)”);
    }
    public void M(object s)
    {
        System.Console.WriteLine(“M(object)”);
    }
}
class Program
{
    static void Main()
    {
        C c = new C();
        c.M(“hello”);
    }
}

(1) writes static M(string)
(2) writes M(object)
(3) uh, dude, this code doesn’t even compile much less run
(4) something else

Think about that for a bit and then try it and see if you were right.

.

.

.

.

.

.

.

In option (1), the compiler could decide that the best match is the static one and let you call it through the instance, ignoring the instance value. In option (2), the compiler could decide that the object version is the best match and ignore the static one, even though the argument match is better. But neither of those actually happens; the rules of C# say that the compiler should pick the best match based on the arguments, and then disallow static calls that are through an instance! The actual result here is therefore (3):

error CS0176: Member ‘C.M(string)’ cannot be accessed with an instance reference; qualify it with a type name instead

What is up with this craziness? If you believe that the rule “static methods should never be accessed through instances” is a good rule – and it seems reasonable – then why doesn’t overload resolution remove the static methods from the candidate set when called through an instance? Why does it even allow the “string” version to be an applicable candidate in the first place, if the compiler knows that it can never possibly work?

I agree that this seems really goofy at first.

To explain why this is not quite as dumb as it seems, consider the following variation on the problem. Class C stays the same.

class B
{
  public C C = new C();
  public void N()
  {
      C.M(“hello”);
  }
}

What does a call to N on an instance of B do?

(1) writes static M(string)
(2) writes M(object)
(3) compilation error
(4) something else

.

.

.

.

.

.

A bit trickier now, isn’t it? Does C.M mean “call instance method M on the instance stored in this.C?” or does it mean “call static method M on type C”? Both are applicable!

Because of our goofy rule we do the right thing in this case. We first resolve the call based solely on the arguments and determine that the static method is the best match. Then we check to see if the “receiver” at the call site can be interpreted as being through the type. It can. So we make the static call and write “static M(string)”. If the instance version had been the best match then we would successfully call the instance method through the property.

So the reason that the compiler does not remove static methods when calling through an instance is because the compiler does not necessarily know that you are calling through an instance. Because there are situations where it is ambiguous whether you’re calling through an instance or a type, we defer deciding which you meant until the best method has been selected.

Now, one could make the argument that in our first case, the receiver cannot possibly be a type. We could have further complicated the language semantics by having three overload resolution rules, one for when the receiver is known to be a type, one for when the receiver is known to not be a type, and one for when the receiver might or might not be a type. But rather than complicate the language further, we made the pragmatic choice of simply deferring the staticness check until after the bestness check. That’s not perfect but it is good enough for most cases and it solves the common problem.

The common problem is the situation that arises when you have a property of a type with the same name, and then try to call either a static method on the type, or an instance method on the property. (This can also happen with locals and fields, but local and field names typically differ in case from the names of their types.) The canonical motivating example is a public property named Color of type Color, so we call this “the Color Color problem”.

In real situations the instance and static methods typically have different names, so in the typical scenario you never end up calling an instance method when you expect to call a static method, or vice versa. The case I presented today with a name collision between a static and an instance method is relatively rare.

If you’re interested in reading the exact rules for how the compiler deals with the Color Color problem, see section 7.5.4.1 of the C# 3.0 specification.

Comments (24)

  1. I remember been quite surprised when I first found out that “Color Color” is a grammar corner case that is specifically covered by the spec in quite a lot of detail and extra special wording. Of course, in retrospect, it makes perfect sense, and I appreciate the fact that it’s there (it does make life easier when coming up with fitting member names).

    It would be interesting to know the design history behind this. Is it something that was considered from the very beginning of C#? Or rather something that only came up when frameworks (I would guess WinForms) ran into the problem?

    This issue first appears in the design notes on June 22nd, 1999. Of course, by that point, people already had started writing the FCL in pre-beta versions of the language, it is entirely possible that this was driven by someone running into the problem in the framework. The notes do not say. — Eric

  2. Sergey Abakumoff says:

    Eric,

    Can you explain why in the following code:

    static void M(object[] array) {…}
    static void M(object obj) { … }

    M(null);

    M(object[] array) is called instead of M(object obj)?

    Well, suppose it had been

    static void M(Animal x ) {…}
    static void M(object x) { … }

    M(new Giraffe());

    Which would you expect to be called? When given the choice between “Animal” and “object”, clearly “Animal” is more specific. We assume you want to call the more specific match when there are two possible matches. All Animals are objects, but not all objects are Animals, so Animal is more specific.

    In your example, null matches both. All arrays are objects but not all objects are arrays, therefore the array one is more specific. The more specific one wins. — Eric

  3. arnshea says:

    I’ve gotta confess that I got this wrong (thought option 2 was correct).  I made the erroneous inference from disallowed behavior (can’t access a static member through an instance reference).  Thinking like a human so often leads one (me?) astray!

    Thanks for illuminating the distinction and giving us a little insight into the order in which these operations (method resolution vs static access) are examined.

  4. commongenius says:

    Unfortunately this also means that in order to call the instance method (in either example), the argument has to be cast to object. Upcasting always leaves a bad taste in my mouth; I would have preferred a solution that required the developer to explicitly remove the ambiguity in either the static case or the instance case by explicitly qualifying the receiver (i.e. global::C or this.C), rather than implicitly selecting an overload by upcasting an argument; the resulting code would be cleaner IMHO.

  5. commongenius says:

    On second thought, there is nothing stopping you from explicitly qualifying the receiver; for some reason the first "solution" I thought of was upcasting, despite that being my least preferred solution.

  6. configurator says:

    commongenius: And what about locals?

    void N() {

       C C = new C();

       C.M("?");

    }

    How would you explicitly qualify the receiver?

  7. Leo Bushkin says:

    Will the same resolution rules be retained when using dynamic types in C# 4.0?

    In other words:

      dynamic C = new C();

      C.M(…);  // what gets called here and why?

    I’ve often wondered whether typing something as dynamic will cause overload resolution to behave differently than it would if they type were known at compile time. There’s already one potential case you can read about here … http://stackoverflow.com/questions/987176/overload-resolution-in-c-4-0-using-dynamic-types

  8. carlos says:

    Having static and instance methods with the same name doesn’t seem terribly useful, it’s not obvious what the compiler will do with them and even when it’s explained people don’t necessarily agree that the compiler is doing the right thing.  If you were starting over would you retain this feature?

  9. Dean Harding says:

    That’s why it’s better if you live in Australia. We have:

    class MyClass

    {

      public Color Colour { get; set; }

    }

    and all is well ๐Ÿ™‚

  10. Simon Buchan says:

    @Dean: As a New Zealander, I believe I can safely say AAARRRGH! ๐Ÿ™‚

  11. Interesting, and nice to see the thought that went into allowing Color Color to work – although, as a side note, that particular class name doesn’t cause me problems as being British I always write Color Colour!! ๐Ÿ™‚

    When starting out with C#, I got caught out with a different problem that’s kind of related (from the point of view of thinking of names for things): you might call it “Color.Color” … in other words, class C in namespace C.  That seems to work less well.

    Indeed, naming a class and namespace the same thing is a bad idea that violates our naming guidelines. I have been meaning to blog about that for a while now. — Eric

  12. Chris Nahr says:

    Carlos: I assume this rule was not put in the C# spec to encourage people to write eponymous static & instance methods (which is indeed terrible design), but rather to allow for inheritance across assemblies that are maintained by different companies, and where such name clashes might occur accidentally.

    Say you get assembly A version 1 with class C that has no static methods, and you derive your own class from A in your own assembly that adds instance method Foo.  Now you get assembly A version 2 that adds a static method C.Foo.  Now what should the C# compiler do — break compilation against the new version?

  13. Weeble says:

    @Luke:

    It was pointed out to me by a colleague that namespaces which are named after the sorts of things they contain could often be better named with a plural. E.g.:

    namespace Animals {

    ____class Animal {}

    ____class Giraffe : Animal {}

    }

    This is mentioned here in the Microsoft Design Guidelines for Developing Class Libraries:

    http://msdn.microsoft.com/en-us/library/ms229026.aspx

    "Consider using plural namespace names where appropriate. For example, use System.Collections instead of System.Collection."

    As an example, there’s System.Net.Sockets.Socket.

  14. Jay Bazuzi says:

    I think "Color Color" should have been disallowed in the runtime; types should have been named differently than members in the guidelines.

    Of course, much of my experience is writing tools for C#, and this would have made my life easier.  Perhaps allowing this really is better for users of the language, but I am doubtful.

    I think we’d be better of with a ‘C’ prefix on classes (and an ‘S’ prefix on structs, protecting us from a set of bugs when we handle structs in a way that only works for reference types).  You may cry "Hungarian", but I point out that we already name interfaces with an ‘I’ prefix, so this change would improve consistency.

  15. Greg says:

    The compiler error should be on the second declaration of method c.M with an error "Cannot define second function with the same name as a static function."

    The error on the call to the function is misdirection and should be avoided.

    Improving the .NET compiler to produce much better diagnosis of these conditions would be great.  Putting significant effort into improved static analysis of C# code would greatly help (e.g., much improved FxCop).   Tools for embedded C++/C have been around doing this in great detail for 20+ years.

  16. TheCPUWizard says:

    Greg…. WGreg…. WHY do you think it should generate an error within the class implementation. There is NOTHING wrong with the class definition. Having Static and Memeber methods with the same name is 100% legal.

  17. TheCPUWizard says:

    Greg,

    While it may not completely conform to all "best practices", I have used a number of design patterns that have static and instance methods with the same name and different parameters to very good effect.

    It tends to occur when one adopts a "pure factory" approach (i.e. "new" is ONLY used inside of a factory method of a class, and never directly in the application). This has a nice "advantage" of being able to support many forms of type substitution (including DI) without ever having to modify the calling code.

    Since "Create" is a logical name for such a function, you get the static/instance overload: one version of Create that is the factory method, and one for creating a new element within the context of an instance.

  18. (Just some constructive (!) feedback.)

    I had a bit of trouble reading this one. C and c were very similar in the font used for the code samples, with the capital being just a pixel taller and wider. When both were on the same line, I could see which one was which, but on its own, I had to read carefully to see if I was looking at the class name or the instance name.

  19. holatom says:

    Great post Eric as always, thanks.

    But what about this code?

       class Bar

       {

           public string Type { get; set; }

           private static Type GetType(string typeName)

           {

               Type type = Type.GetType(typeName, false, true); //<-compile error

               return type;

           }

       }

    This code failed to compile with error CS0120: An object reference is required for the non-static field, method, or property ‘Test.Bar.Type.get’ at Type.GetType(typeName, false, true) method call.

    Of course if you renamed "Bar.Type" property to something else it fixed the problem.

  20. TheCPUWizard says:

    Holatom,

    Eric can confirm, but I believe it is because the original item was about overloading multiple methods and resolution based upon signature while your example is about resolution of a Type (no pun intended) and a Property; and I believe (donโ€™t have the spec handy) a Property will always โ€œtrumpโ€ (not Donald) a Type in this condition.

    David

  21. holatom says:

    Thanks, you are most likely right, because in this case is problem with "Type" identifier not in actual GetType() method call.

    It seems that this is "only" inconsistency between C# compiler and VS 2008, because VS 2008 colours "Type" identifier in code above as class (not as normal identifier) and intelliSense is not working either (neither as string reference or Type class).

  22. ichian01 says:

    I’m curious as to why during the design of C# the call to static methods was done through . just like a call to instance methods, instead of through say ::

    Which then clearly separates what’s static and what’s not.  Because as reading the second code option, it’s quite ambiguous.  

    What’s done is done and can’t be changed, but there must have been a reason or it was under a particular context.

  23. quetzalcoatl says:

    I can only guess, that that a copy cat from Java’a syntax, where you do just the same thing, and the only difference is whever you do have an object ref, or a class name to the left side of the dot-operator.

    Btw. I *hate* the feature of calling statics via object reference. It’s sick. You should never be able to directly call static method X having an object on the left side. It breaks the barrier with object methods and free functions [which the statics are really are]. Pah, if you allow to call My::StaticFunc via myobj.StaticFunc, why not allow the static to be VIRTUAL at all??? as the actual class of myobj changes, runtime could pick the actual member override, or the static (override) from actual class instead of hardwiring the call to the static taken from the declared class of the variable ‘myobj’.

    And to mention that if you change the type of ‘myobj’ variable, the call gets instaneously wrong, misleading or simply uncompilable.

    The problem may apply also to one of the latest addition, the ‘extension methods’ that are in fact statics but (via language syntax sugar) are behaving like methods. Issues with them are however much lighter cases, as the extensions *require* supplying of the ‘this’ parameter, and thus logically are miiight beee seen as methods, not functions, but without private/protected access granted. Personally, I’d still argue that this is breaching the barrier of clear scoping and produced ambiguous code. Ambiguous for people, not the compiler [try to find where the extension method is defined, when someone else forgot to provide correct using clause, doh!], but unfortunatelly they’are all too useful due to sealed/internal/nomultiinheritance/nomixins features of the language ๐Ÿ™

    Yep, I’m from C++ tribe, my point of view is further bended due to not so small experience in creating compilers and VMs/runtimes, but I love loose coupling and dynamism like in Ruby. and I’m strict about few things. But even in Ruby trying to call static method [there – called ‘class method’ opposed to ‘instance method’] on an object that is NOT class [in Ruby classes are mutable object], results in crash/error/exception. Simply: object x of class X doesnt HAVE method X.do. Class owns it.