www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Faking constructors! An overview of object layout.

I can fake constructors so they work as long as you don't cast to 
interfaces.

The way Walter has casting to interfaces is pretty clever. An object is 
laid out in memory like so:

vtbl ptr
guts

The guts are laid out as follows:
    super.guts
    this.tupleof
    interface-0
    interface-1...

interface-n is a pointer to an Interface struct. (This seems to be the 
only way of accessing these structs.)

Then, in order to cast something to interface n, you just increment the 
pointer to interface-n.

The awkward part is finding if you can cast to a particular interface, 
since the interface array for each type doesn't contain the interfaces 
that base classes implement. You have to go through each interface that 
this class implements directly to see if they are or inherit from the 
target, and you have to repeat that for each base class up to Object.

This means that, in order to fake constructors, you have to do something 
like:

// (public domain)
T create(T)() {
    void** _this = cast(void**)malloc(__traits(classInstanceSize, T));
    *_this = T.classinfo.vtbl.ptr;
    setInterfaces(_this, T.classinfo);
    T ret = *cast(T*)&this;

    // gc.setTypeInfo might do this
    if (typeid(T).flags == 1)
       gc.hasPointers(_this);
    else
       gc.hasNoPointers(_this);

    // call constructor?
    return ret;
}
void setInterfaces(void** _this, ClassInfo type) {
     if (type.base !is null) {
         setInterfaces(_this, type.base);
     }
     foreach (iface; type.interfaces) {
         // This should work but doesn't: according to the spec, for an
         // interface, vtbl[0] is a ptr to the Interface struct, but it's
         // not, which means the only way to get the Interface ptr is by
         // using a constructor -- begging the question.
         auto ptr = iface.classinfo.vtbl[0];
         *(_this + (iface.offset / (void*).sizeof)) = ptr;
     }
}


I had to reverse engineer this. Don't let this happen to you! Now that 
there exists <http://digitalmars.com/d/phobos/object.html>, you need 
never do this again! Just four easy payments of $19.95.

Well, okay, the spec doesn't say straight out that Classinfo.interfaces 
only includes those immediately implemented by this class. Other than 
that, it's in the spec.

I thought this might be useful, in case someone else is doing stuff with 
proxying objects and the like.
Dec 02 2007