https://issues.dlang.org/show_bug.cgi?id=14612
Issue ID: 14612 Summary: typeid(interface) returns TypeInfo_Class object Product: D Version: D2 Hardware: All OS: All Status: NEW Severity: normal Priority: P1 Component: DMD Assignee: nob...@puremagic.com Reporter: k.hara...@gmail.com In the following test code, typeid(i) does not return typeid(J) typed TypeInfo_Interface, rather it returns typeid(J).info that is TypeInfo_Class. import std.stdio; interface I {} interface J : I {} class C : J {} class D : C {} void main() { D d = new D(); Object o = cast(Object)d; I i = cast(I)d; writeln(typeid(d) is typeid(D)); // true writeln(typeid(o) is typeid(D)); // true writeln(typeid(i) is typeid(I)); // false ? writeln(typeid(i) is typeid(J)); // false ? writeln(typeid(i) is typeid(D)); // false ? writeln(typeid(i)); // prints 'test.J' !? // old exp.classinfo property is same with typeid(exp) writeln(d.classinfo is typeid(D)); // true writeln(o.classinfo is typeid(D)); // true writeln(i.classinfo is typeid(J)); // false, same with typeid() writeln(i.classinfo is typeid(I)); // false, same with typeid() writeln(i.classinfo is typeid(D)); // false, same with typeid() writeln( typeid(i) is typeid(J).info); // true writeln(i.classinfo is typeid(J).info); // true } ---- This nonintuitive behavior comes historically from D1. In D1, ClassInfo, TypeInfo_Class, and TypeInfo_Interface are different classes. In there, ClassInfo had had the information of class *and* interface definition in runtime, and two TypeInfo-s were purely identity objects that associated with the class/interface types. In D2, ClassInfo and TypeInfo_Class were merged into one (by issue 3380 ?). Now ClassInfo is an alias name of TypeInfo_Class. But, the separation between ClassInfo and TypeInfo_Interface is still there. And currently, typeid(i) is completely same with i.classinfo, therefore it still returns ClassInfo == TypeInfo_Class. ----- I think there's two ways to fix the behavior. 1. To make TypeInfo_Interface accessible from runtime interface references. To do that, change object.Interface struct as follows: struct Interface { version(none) // old { TypeInfo_Class classinfo; } else // new { TypeInfo_Interface tinfo; @property TypeInfo_Class classinfo() { return tinfo.info; } } void*[] vtbl; size_t offset; } and then the interface vtb[0] will be the runtime TypeInfo_Interface that we needing. Pros: We need very little compiler and druntime changes. Cons: It would add a small runtime cost in the dynamic cast. See: druntime/src/rt/cast_.d 2. Separate ClassInfo from TypeInfo_Class again and define TypeInfo hierarchy as follows: abstract class ClassInfo : TypeInfo { ... } class TypeInfo_Class : ClassInfo { ... } class TypeInfo_Interface : ClassInfo { ... } Pros: By handling ClassInfo, the runtime cost in dynamic cast operation can be kept same with today's. Cons: If an user still using the name 'ClassInfo', the code behavior will be changed. --