emulate with

Simen Kjærås simen.kjaras at gmail.com
Fri May 31 08:35:23 UTC 2019


On Friday, 31 May 2019 at 07:17:22 UTC, Amex wrote:
> What I'm talking about is that if A would be dispatched to, 
> say, W!X where W handles the special dispatching by returning 
> X_A rather than X.A.
>
>
> I don't know if D can do this kinda stuff even though it would 
> be rather simple as it would depend on with.

Of course D can! However, it's not really pretty, and I think I 
found a bug in the process.

This is my code that compiles and runs:

void X_A(int i) {}
void X_A(string s) {}
void X_B(int i) {}
void X_C_Q(int i) {}

unittest {
     with (Dispatcher.X!({})) {
         A(1);
         A("a");
         B(2);
         C_Q(3);
     }
}

template getMethod(alias x, string name) {
     static if (__traits(hasMember, x, name)) {
         alias getMethod = __traits(getMember, x, name);
     } else static if (x.stringof[0..7] == "module ") {
         import std.meta : AliasSeq;
         alias getMethod = AliasSeq!();
     } else {
         alias getMethod = getMethod!(__traits(parent, x), name);
     }
}

struct Dispatcher {
     template opDispatch(string prefix) {
         static auto opDispatch(alias context)() {
             struct WithObject {
                 auto opDispatch(string name, A...)(A a) {
                     struct OverloadCaller {
                         auto opCall(Args...)(Args args) {
                             return getMethod!(context, 
prefix~"_"~name)(args);
                         }
                     }
                     OverloadCaller result;
                     return result;
                 }
             }
             return WithObject();
         }
     }
}

So, the ugly:

1) Instead of just Dispatcher.X, we need to give Dispatcher a 
context from where to look for X_<something>. That's the curly 
brackets in Dispatcher.X!({}).

2) The bug I mentioned. The whole OverloadCaller deal is a silly 
workaround for WithObject's opDispatch not being called correctly 
by DMD. That's also why WithObject's opDispatch takes (A...)(A 
a). I'll be filing this, of course.

3) with doesn't correctly handle static opDispatch. I'll be 
filing a bug for that as well.

We could fix 1) by introducing a new magic identifier - something 
like __CONTEXT__, which would work somewhat like __FUNCTION__, 
but be useful for reflection with __traits. I've played a little 
with this idea, but I'm not ready to make a PR with it.

With 1), 2) and 3) fixed, the code would look like this (only 
changed code included):

unittest {
     with (Dispatcher.X) {
         A(1);
         A("a");
         B(2);
         C_Q(3);
     }
}

struct Dispatcher {
     struct opDispatch(string prefix, alias context = __CONTEXT__) 
{
         static auto opDispatch(string name, Args...)(Args args) {
              return getMethod!(context, prefix~"_"~name)(args);
         }
     }
}

I think that's kinda neat, TBH.

--
   Simen


More information about the Digitalmars-d-learn mailing list