On 10/26/2016 10:48 AM, pontius wrote:
> Apologies for the long post or stupid questions, I only started to learn
> D today.

Looking at what you've achieved in one day, we really need you! :)

> I have a use case where various types (A, B, C) need to be associated
> with instances of different classes (ManagerA, ManagerB, ManagerC). A
> certain object (globalManager) should redirect operations on those types
> to their respective managers at compile-time. I intend to use it in the
> following way:
>
> class GlobalManager(TypeToManagerMapping) {
>     public void process(T)(T t) {
>         // Must be resolved at compile-time
>         TypeToManagerMapping.getManagerForType(T).process(t);
>     }
> }
>
> // All these types can be completely unrelated, i.e. no base classes
> struct A {}
> alias ManagerA = DefaultManager!(A)
> struct B {}
> alias ManagerB = DefaultManager!(B)
> struct C {}
> alias ManagerC = SomeCustomManager;
>
> // Calls to globalManager should be redirected to these at compile-time
> auto mgrA = new ManagerA();
> auto mgrB = new ManagerB();
> auto mgrC = new ManagerC();
>
> // This is my problem, see below
> alias TypeToManagerMapping = ...;
>
> // Pass the mapping as a template parameter so that it can be resolved
> at compile-time
> auto globalManager = new GlobalManager!(TypeToManagerMapping)();
>
> // The following is the module user's code.
> // The user may not be aware of mgrA, mgrB, etc, only of globalManager
>
> A a = A();
> B b = B();
> C c = C();
>
> // Redirection to managers in the following operations
> // must be resolved at compile-time
>
> // Should turn into mgrA.process(a), etc
> globalManager.process(a);
> globalManager.process(b);
> globalManager.process(c);

void report(M, T)() {
    import std.stdio : writefln;
    writefln("%s is managing an object of %s", M.stringof, T.stringof);
}

class DefaultManager(T) {
    void manage(T t) {
        report!(typeof(this), T);
    }
}

class SomeCustomManager {
    void manage(C c) {
        report!(SomeCustomManager, C);
    }
}

struct A {}
alias ManagerA = DefaultManager!(A);
struct B {}
alias ManagerB = DefaultManager!(B);
struct C {}
alias ManagerC = SomeCustomManager;

/*/ You can use this:

alias TypeToManagerMapping = AliasSeq!(A, ManagerA,
                                       B, ManagerB,
                                       C, ManagerC);
However, if you already have symbolic mapping from T to ManagerT, you can use string mixins as well
*/
template ManagerRegistrationFor(T) {
    // Just a couple of convenience functions
    string managerType() { return "Manager" ~ T.stringof; }
    string managerName() { return "mng" ~ T.stringof; }

    // This is the manager object
    mixin(managerType() ~ ' ' ~ managerName() ~ ';');

    // This is the initialization of it
    static this() {
        mixin(managerName() ~ `= new ` ~ managerType() ~ ';');
    }

    void manage(T obj) {
        // Dispatches to the manager
        mixin(managerName() ~ ".manage(obj);");
    }
}

struct GlobalManager {
    void process(T)(T t) {
        manage(t);
    }
}

GlobalManager globalManager;

mixin ManagerRegistrationFor!A;
mixin ManagerRegistrationFor!B;
mixin ManagerRegistrationFor!C;

/* The above could be specified with an AliasSeq (uncompiled):

alias ManagedTypes = AliasSeq!(A, B, C);

This loop can be inside a template like RegisterManagedTypes

foreach (T; ManagedTypes) {
    mixin ManagerRegistrationFor!T;
}

And then:

mixin RegisterManagedTypes;

*/

void main() {
    A a = A();
    B b = B();
    C c = C();
    globalManager.process(a);
    globalManager.process(b);
    globalManager.process(c);
}

There are different approaches but I think the solution above achieves what you want:

DefaultManager!(A) is managing an object of A
DefaultManager!(B) is managing an object of B
SomeCustomManager is managing an object of C

Ali

Reply via email to