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 (17)

  1. Hasani says:

    class B : A<B>

    should be

    class B<X> : A

    or

    class B<X> : A<Y>

    I noticed, B is defined twice in the fifth line your code. Maybe that confused the compiler as it has confused me 😉

  2. tzagotta says:

    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.

  3. 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).

  4. Still a good puzzle though (and ok, it still took me a minute or two to re-train my brain to think inside out in the right way).

    The fix (implied but not actually stated in my previous comment) is to change the override line to read "public override A<B>.B getT()".

  5. Keith Farmer says:

    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.

  6. Jeff Lewis says:

    The line:

    public override B getT()

    Should be:

    public override T getT()

  7. geoff.appleby says:

    Yup, crashes my IDE as well – at least, it consumes 100% cpu and I have to kill it off.

    It dies specifically when I type the "<B" in "class B : A<B>". It’s also the line I was suspicious of when I first read the code.

    Interestingly though, I converted that code to VB and it compiles fine, and my IDE survives 🙂

    Public MustInherit Class A(Of T)

    Public MustOverride Function getT() As T

    Class B

    Inherits A(Of B)

    Public Overrides Function getT() As A(Of T).B

    Throw New System.Exception("The method or operation is not implemented.")

    End Function

    End Class

    End Class

  8. Ryan says:

    Teaches me to copy code from the RSS feed without looking at the comments first. I just lost a bit of work…

  9. 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?

  10. Hey, how come my comments giving the answer aren’t showing up?

  11. 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 😉

  12. Jeswin P. says:

    Changing

    public override B getT()

    To

    public override A<T>.B getT()

    compiles properly.

  13. barrkel says:

    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.

  14. 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? 🙁

  15. geoff.appleby says:

    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.

  16. 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?