|
complaining 24h/day, although not always in print |
July 29, 2007
What is an Inner Class?
Eric Lippert gave and inheritance puzzle which got me thinking about some pathological programming.
What is an inner class? And should inner classes be used for simple implementation hiding, or do they mean more?
Let's add myVar to A<T> from Eric's example:
public class A<T> {
public T myVar;
public class B : A<int> {
public void M() {
System.Console.WriteLine(typeof(T).ToString());
}
public class C : B { }
}
}
The fundamental problem I see is peoples' automatic assumption that B has only one relationship with A, namely inheritance. In fact B has two relationships with A, the second being many-to-one inner-to-outer class relationship.
Inner classes have a magic field, call it "_parent_", which point to an instance of the outer class. Essentially, inner classes are convenient many-to-one relationships. Programmers should not be able to instantiate an inner class without a reference to an *instance* of the outer class in order to ensure _parent_ is defined. Only the obscene would use inner/outer classes where namespaces are intended.
{
new A<string>.B.C(); //SHOULD FAIL COMPILATION
}
The proper way to make an instance of A<string>.B.C is
{
A<string> a=new A<string>;
A<string>.B b=new a.B;
A<string>.B.C c=new b.C;
}
Let K be a member of A<T>, in this example K will be A<string>
These two facts about B are independent and do not conflict:
1) B is an inner class of K, and so has a field "_parent_" of type K.
2) B inherits from A<int>
The answer to the question "What B does C inherit from?" is "There is only one B" . This one B is a little more complicated:
Given b, an instance of A<string>.B, b.myVar is ambiguous. It can mean
A) b._parent_.myVar (of type string)
B) ((A<int>)b).myVar (of type int)
I think it is clear that A<int>.B.M will output "int" and A<string>.B.M will output "string". If only because none of us disagree.
Moving on to C
In an almost same manner:
1) C is an inner class of B, and so has a field "_parent_" of type B.
2) C inherits from B
Given c, an instance of A<string>.B.C, c.M is ambiguous. It can mean
C) c._parent_.M (outputs "string")
D) ((B.c).M (outputs "string")
Therefore "c.M()" in MainClass.Main should NOT compile.
UPDATE (June 30)
Of course, with C# the unintuitive result is a side effect of priority ordering ambiguous attributes instead of just reporting the ambiguity as an error.