Search code examples
dmetaclassclass-reference

Are there metaclasses or class reference in D?


Are there any system of classe reference in D? To be more accurate I look for the equivalent of the Delphi

TMyClassRef = class of TMyClass;

This would be used for a factory (just like in the Object but without using the class name):

// ideally
void AddNew(*TBaseClass APtr, /*?class_ref_type?*/ AClassType)
{
    *APtr = new AClassType;
}

Currently I do this:

void AddNew(*TBaseClass APtr)
{
    *APtr = new typeof(*APtr);
}

But the problem is that typeof() returns always TBaseClass and never a sub class of TBaseClass (when a sub class is passed as parameter). This is clearly a case where class references would be used in Delphi but the D language doesn't seem to have such a system.


Solution

  • Maybe I'm completely missing the idea in Delphi, but this seems to be what a templates are for:

    import std.stdio;
    
    class Parent {
        string inherited() {
            return "Hello from parent";
        }
    
        override string toString() {
            return "Hello from parent";
        }
    }
    
    class Child : Parent {
        override string toString() {
            return "Hello from child";
        }
    }
    
    void add(C, P)(P* ptr) {
        *ptr = new C;
    }
    
    void main() {
        Parent t;
        writeln(t); // prints null
    
        add!Child(&t);
        writeln(t); // prints Hello from child
        writeln(t.inherited()); // prints Hello from parent
    }
    

    This way you pass in the type you want to instantiate instead of an instantiated object of that type. This should generate compile errors if C is not a child of P in add().

    Edit:

    If you want to be more specific with add, you could do this:

    void add(T : Parent)(Parent* ptr) {
        *ptr = new T;
    }
    

    To make things nicer, use an out parameter to be more idiomatic:

    void add(T : Parent)(out Parent ptr) {
        ptr = new T;
    }
    void main() {
        Parent p;
        add!Child(p);
    }