Interface "indexing"

anonymous via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun Sep 6 12:44:33 PDT 2015


On Sunday 06 September 2015 19:32, Prudence wrote:

> Any ideas?

As far as I understand (which may not be very far), you'd like to avoid 
keeping a list of the types that's separate from the type declarations 
themselves.

Let's start with some code where the list is manually kept in sync with the 
types:

----
import std.stdio;
import std.typetuple;

interface I {void go();}

class A : I {void go() {writeln("'Allo 'Allo!");}}
class B : I {void go() {writeln("Bonjourno!");}}
class C : I {void go() {writeln("Cha cha ciao!");}}

alias Types = TypeTuple!(A, B, C); /* You'd like to avoid this, right? */

I create(uint index)
{
    switch(index)
    {
        /* Note how the switch cases are generated with (static) foreach: */
        foreach(i, T; Types)
            case i: return new T;
        default: throw new Exception("");
    }
}

void main()
{
    auto a = create(0);
    a.go(); /* 'Allo 'Allo! */
    
    auto b = create(1);
    b.go(); /* Bonjourno! */
    
    auto c = create(2);
    c.go(); /* Cha cha ciao! */
    
    auto d = create(3); /* throws exception */
}
----

To avoid having to touch two places when you add a class, you can use a 
somewhat obscure feature of D, the NewAnonClassExpression:

----
alias Types = TypeTuple!(
    typeof(new class () I {void go() {writeln("'Allo 'Allo!");}}),
    typeof(new class () I {void go() {writeln("Bonjourno!");}}),
    typeof(new class () I {void go() {writeln("Cha cha ciao!");}}),
);
----

The syntax is described here: http://dlang.org/class.html#anonymous

Another alternative is to generate `Types` by getting all members of the 
module and filtering out everything that doesn't implement I:

----
class A : I {void go() {writeln("'Allo 'Allo!");}}
class B : I {void go() {writeln("Bonjourno!");}}
class C : I {void go() {writeln("Cha cha ciao!");}}

template IfImplementsI(string thing_s)
{
    alias thing = TypeTuple!(__traits(getMember, module_, thing_s));
    static if (is(thing[0] : I) && !is(thing[0] == I))
        alias IfImplementsI = thing;
    else alias IfImplementsI = TypeTuple!();
}

alias module_ = TypeTuple!(__traits(parent, {}));
alias Types = staticMap!(IfImplementsI, __traits(allMembers, module_));
----

That can probably be done more elegantly.

I'm sure one could also generate an enum with nice names along with that, so 
that it's not `create(0)` but `create(MyEnum.A)`.


More information about the Digitalmars-d-learn mailing list