www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 14612] New: typeid(interface) returns TypeInfo_Class object


          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: nobody puremagic.com
          Reporter: k.hara.pg 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

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

May 20 2015