C# Stumper: Why does this code not compile?

Hey folks,

First off, I want to appologize for not having any activity on my blog for a while. I just got back from a wonderful 3 week vacation in Spain. Now that I'm back, rested and limber, here's a twisted peice of C# code which is gauranteed to turn your brain inside out.

Why does the compiler (correctly) give an error message on the override in the following code?

abstract class A<T>
{
    public abstract T getT();

class B : A<B>
    {
        public override B getT()
        {
            throw new System.Exception("The method or operation is not implemented.");
        }
    }
}

I got this code from a coworker, and I must confess that the first time I saw it I was convinced that the behaviour was a compiler bug. It turns out that the compiler correctly diagnoses the problem, though even after seeing the error message it took me a while to figure out what's going on. I'll post a discussion in a couple of days.

Any Takers?

Peter

C# Guy

Comments

  • Anonymous
    November 09, 2005
    The comment has been removed
  • Anonymous
    November 09, 2005
    This code crashes my installation of the RTM VS2005 IDE! It crashes it if I copy/paste the code in, or if I type it in.
  • Anonymous
    November 09, 2005
    Easy (at least if you read and grokked the fullness of Cyrus's (I think) similar quiz a few months ago which stumped me for DAYS).

    The base class getT() returns A<B>.B (because B inherits from A<B>) while the derived class getT() returns A<T>.B (because it's taking the B from the containing scope).
  • Anonymous
    November 09, 2005
    The comment has been removed
  • Anonymous
    November 09, 2005
    tzagotta: The crash is probably the known infinite recursion bug in the IDE. It's something, I believe, that the C# IDE team's already looking into a hotfix for.
  • Anonymous
    November 09, 2005
    The comment has been removed
  • Anonymous
    November 09, 2005
    The comment has been removed
  • Anonymous
    November 09, 2005
    Teaches me to copy code from the RSS feed without looking at the comments first. I just lost a bit of work...

  • Anonymous
    November 09, 2005
    I'm running VS2005 beta2 (doing some WCF development) and I got the compiler error you spoke
    about Peter. The problem is that since B is an internal class inside A<T>, in otherwords A<T>.B.

    Your method signature for the override should be public override A<T>.B getT() since that's B's
    actual type name. The code should look like this:


    abstract class A<T>
    {
    public abstract T getT();

    class B : A<B>
    {
    public override A<T>.B getT()
    {
    throw System.Exception("The method or operation is not implemented.");
    }
    }
    }

    If you use the code snippets feature of the IDE to create the implemenation of the override in
    class B, you will get this signature:

    public override B getT()

    Which as mentioned is wrong. However, if you implement the class in VB.NET like Geoff did, then
    the IDE gets your the right signature

    ' VB.NET Code
    public overrides Function getT() as A(Of T).B

    // C# code
    public override A<T>.B getT()

    (This seems to be in the case in VS2005 beta2. I'm not sure about RTM.)

    Aren't generics fun?
  • Anonymous
    November 09, 2005
    Hey, how come my comments giving the answer aren't showing up?
  • Anonymous
    November 09, 2005
    I don't know why my posts aren't showing up, but I found Cyrus's quiz earlier that allowed me to figure this one out so quickly.

    http://blogs.msdn.com/cyrusn/archive/2005/08/01/446431.aspx

    If you read my comments on that one you can see my brain gradually turning inside out until the answer made sense ;)
  • Anonymous
    November 09, 2005
    Changing
    public override B getT()
    To
    public override A<T>.B getT()
    compiles properly.

  • Anonymous
    November 09, 2005
    Geoff: your code isn't identical. The return type of your overridden getT() is (in C#) A<T>.B, while the C# code Peter posted returns B from the overridden getT().

    The reason the original C# code doesn't compile is that there are two B's:

    1) A<B>.B, nested inside the A<B> that B derives from, in scope because of inheritance.

    2) The outermost B, A<T>.B, the one that is being defined, in scope because of lexical nesting.

    It appears that the inherited A<B>.B is what is being referred to when B is used nakedly, as in the example, when it should refer to the outer B, A<T>.B, which is the return-type of the overridden method.

    I'm not intimiately familiar with the precedence of scope nesting in C#: it appears that the inheritance scope of a nested class comes ahead (or is pushed on the scope stack last, if you will) of the immediate outer lexical scope. Interesting.
  • Anonymous
    November 10, 2005
    Ok, I'm confused. I posted a whole bunch of comments, the first before 5pm EST yesterday giving the same correct solution that barrkel gave this morning and pointers to other relevant articles, and none of them showed up.

    I'm making this post from IE in case the blog is blocking postings from Firefox...

    What's wrong with my comments? :(
  • Anonymous
    November 10, 2005
    Barry: Yeah, I know mine's not identical, it's also correct laughs

    OK, maybe not correct, but it's what the VB ide inserted for me with all it's autocomplete stuff.
  • Anonymous
    November 10, 2005
    I'm running VS2005 beta2 (doing some WCF development) and I got the compiler error you spoke
    about Peter. The problem is that since B is an internal class inside A<T>, in otherwords A<T>.B.

    Your method signature for the override should be public override A<T>.B getT() since that's B's
    actual type name. The code should look like this:


    abstract class A<T>
    {
    public abstract T getT();

    class B : A<B>
    {
    public override A<T>.B getT()
    {
    throw System.Exception("The method or operation is not implemented.");
    }
    }
    }

    If you use the code snippets feature of the IDE to create the implemenation of the override in
    class B, you will get this signature:

    public override B getT()

    Which as mentioned is wrong. However, if you implement the class in VB.NET like Geoff did, then
    the IDE gets your the right signature

    ' VB.NET Code
    public overrides Function getT() as A(Of T).B

    // C# code
    public override A<T>.B getT()

    (This seems to be in the case in VS2005 beta2. I'm not sure about RTM.)

    Aren't generics fun?

  • Anonymous
    June 16, 2009
    PingBack from http://topalternativedating.info/story.php?id=7787