An Inheritance Puzzle, Part One

An Inheritance Puzzle, Part One

  • Comments 24

Once more I have returned from my ancestral homeland, after some weeks of sun, rain, storms, wind, calm, friends and family. I could certainly use another few weeks, but it is good to be back too.

Well, enough chit-chat; back to programming language design. Here's an interesting combination of subclassing with nesting. Before trying it, what do you think this program should output?

public class A<T> {
    public class B : A<int> {
        public void M() {
            System.Console.WriteLine(typeof(T).ToString());
        }
        public class C : B { }
    }
}
class MainClass {
    static void Main() {
        A<string>.B.C c = new A<string>.B.C();
        c.M();
    }
}

Should this say that T is int, string or something else? Or should this program not compile in the first place?

It turned out that the actual result is not what I was expecting at least. I learn something new about this language every day.

Can you predict the behaviour of the code? Can you justify it according to the specification? (The specification is really quite difficult to understand on this point, but in fact it does all make sense.)

(The answer to the puzzle is here.)

  • Sorry, I prefer to err on the side of politeness...

    As far as B inheriting T....  I was trying to infer the inner workings here, to explain why in the world the example would yield int instead of string.  Some sort of weird inheritance of T was the only way I could figure that this would happen.

    Obviously there's some assumption I'm making that is wrong.  Either I don't understand the scoping rules, or I've got the order in which things happen all mixed up.

    I still think it _should_ output string.  =P

    Sigh....  I'll wait for Monday.

  • Took me a few minutes to grasp this one.  The <T> is clearly referring to the containing class.  Which means that b.M() shows a string. But the container class for c is b - which is A<Int>.

    So yes, that makes sense - just took a moment to get there.

  • Hi,

    public class A<M> {

    public class X<T> {

       public class B : A<int> {

           public new void M() {

               System.Console.WriteLine(typeof(T).ToString());

               System.Console.WriteLine(typeof(M).ToString());

           }

           public class C : B { }

       }

    }

    ...

    A<string>.X<double>.B.C c = new A<string>.X<double>.B.C();

           c.M();

    Prints string and double.

    And why do I need the new keyword in M here?

    Your postings are way shorter than Chris Brumme's when he was still posting, but I am finding myself equally confused after reading them (I love that). So I guess you can consider yourself much more efficient:-)

  • Steve:

    Excellent example!  Why is it that this DOESN'T reproduce the odd behaviour? The germane difference between the two is that in your example, A<T> does not contain anything called B.

    When I post what is really happening on Monday it'll be clear why this does what it does.

    You need the "new" because your method M shadows the in-scope type variable M from A<M>.  We try to make it either illegal to shadow like this, or make you put the keyword "new" on one of them as a big waving red flag that says "there is a name ambiguity involving this method, so keep that in mind when you are reading this code".

  • Today, the answer to Friday's puzzle . It prints "Int32". But why? Some readers hypothesized that M would

  • Hi Eric, I have a confusion, you mentioned that ** the question hinges solely upon what "B" means in "class C : B", and in this case it means A<int>.B. **

    So, if you consider the following code

    A<string>.B b = new A<string>.B();          

    b.M();

    Why in this case b.M() prints String not INT32 , here also "B" should be considered as A<int>.B ... what's your comment ....

  • Hi Eric,

    If we modify the code like this ..

    public class A<T>

       {

           public void N()

           {

               Console.WriteLine(typeof(T).ToString());

           }

           public class B : A<int>

           {

               public void M()

               {

                   Console.WriteLine(typeof(T).ToString());

               }

               public class C : B

               {

               }

           }

       }

       static void Main()

           {

               A<string>.B b = new A<string>.B();          

               b.M();

               b.N();

    Here, b.M() shows String but b.N() shows Int32.  I am confused how could it happen.....

  • 如果我们的代码中同时出现泛型、继承、嵌套类这三种语言元素,那么在根据名称解析类型的时候可能就会有歧义了。本文中的问题及其结论是非常有意思的,其分析过程也非常的绕,大家一起来讨论下吧:)

  • 如果我们的代码中同时出现泛型、继承、嵌套类这三种语言元素,那么在根据名称解析类型的时候可能就会有歧义了。本文中的问题及其结论是非常有意思的,其分析过程也非常的绕,大家一起来讨论下吧:)

Page 2 of 2 (24 items) 12