www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Retreive method given object, name and arguments

reply Michael Coulombe <kirsybuu gmail.com> writes:
Is there a way to implement "getSymbolOfCall" and 
"getDelegateOfCall" such that doit is functionally equivalent to 
calling the method directly?

auto doit(C, string methodName, Args...)(C c, Args args) {
     alias methodSymbol = getSymbolOfCall!(c, methodName, Args);
     pragma(msg, hasUDA!(methodSymbol, "my attr"));
     auto dg = getDelegateOfCall!(c, methodName, Args);
     return dg(args);
}

They should deal with getting the right overload, opDispatch-ing, 
and deducing template arguments from the real argument list to 
get a concrete delegate pointer. methodSymbol should give access 
to compile-time introspection like full signature and UDAs.

The ability to do this for non-member functions would be cool 
too, but is beyond my use case.
Aug 11 2016
next sibling parent Lodovico Giaretta <lodovico giaretart.net> writes:
On Thursday, 11 August 2016 at 20:27:51 UTC, Michael Coulombe 
wrote:
 Is there a way to implement "getSymbolOfCall" and 
 "getDelegateOfCall" such that doit is functionally equivalent 
 to calling the method directly?

 auto doit(C, string methodName, Args...)(C c, Args args) {
     alias methodSymbol = getSymbolOfCall!(c, methodName, Args);
     pragma(msg, hasUDA!(methodSymbol, "my attr"));
     auto dg = getDelegateOfCall!(c, methodName, Args);
     return dg(args);
 }

 They should deal with getting the right overload, 
 opDispatch-ing, and deducing template arguments from the real 
 argument list to get a concrete delegate pointer. methodSymbol 
 should give access to compile-time introspection like full 
 signature and UDAs.

 The ability to do this for non-member functions would be cool 
 too, but is beyond my use case.
Maybe I'm not understanding correctly, but I think you can use string mixins: auto doit(string methodName, C, Args...)(C c, Args args) { mixin("return c." ~ methodName ~ "(args);"); }
Aug 11 2016
prev sibling next sibling parent reply ketmar <ketmar ketmar.no-ip.org> writes:
On Thursday, 11 August 2016 at 20:27:51 UTC, Michael Coulombe 
wrote:


import std.stdio;

struct S {
   void foo () { writeln("foo()"); }
   void foo (int n) { writeln("foo(", n, ")"); }
}


auto doit(string methodName, C, Args...) (C c, Args args) {
   static if (is(typeof(mixin("c."~methodName~"(args)")))) {
     mixin("return c."~methodName~"(args);");
   } else {
     throw new Exception("no method '"~methodName~"' in type 
"~C.stringof);
   }
}


void main () {
   S s;
   s.doit!"foo"(42);
   s.doit!"foo"();
   s.doit!"oops"(); // this throws
}


of course, you can replace `static if` with `static assert` to 
turn it into compile-time error.
Aug 11 2016
parent ketmar <ketmar ketmar.no-ip.org> writes:
On Thursday, 11 August 2016 at 20:41:33 UTC, ketmar wrote:
ah, my bad, i missed UDA part of the question. sorry. ;-)
Aug 11 2016
prev sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
On Thursday, 11 August 2016 at 20:27:51 UTC, Michael Coulombe 
wrote:

here is something for you to play with:


import std.stdio;

enum CallAllowed0;
enum CallAllowed1;

struct S {
    CallAllowed0 void foo () { writeln("foo()"); }
    CallAllowed1 void foo (int n) { writeln("foo(", n, ")"); }
}


bool hasGoodMethod(string methodName, UDA, C, Args...) () {
   import std.traits: hasUDA;
   bool res = false;
   alias Identity(T...) = T[0];
   foreach (string mem; __traits(allMembers, C)) {
     static if (mem == methodName) {
       static if (is(typeof(__traits(getMember, C, mem)))) {
         alias mx = Identity!(__traits(getMember, C, mem));
         foreach (auto t; __traits(getOverloads, C, mem)) {
           static if (hasUDA!(t, UDA)) {
             static if (is(typeof((Args args) { auto dg = &t; 
dg(args); }))) {
               res = true;
               break;
             }
           }
         }
       }
     }
   }
   return res;
}

auto doit(string methodName, UDA, C, Args...) (C c, Args args) {
   static if (hasGoodMethod!(methodName, UDA, C, Args)) {
     mixin("return c."~methodName~"(args);");
   } else {
     static assert(0, "can't call method '"~methodName~"' in type 
"~C.stringof);
   }
}


void main () {
   S s;
   version(v0) {
     s.doit!("foo", CallAllowed0)(42);
   } else version(v1) {
     s.doit!("foo", CallAllowed1)(42);
   } else version(v2) {
     s.doit!("foo", CallAllowed0)();
   } else version(v3) {
     s.doit!("foo", CallAllowed1)();
   } else {
     static assert(0, "version?");
   }
}


% rdmd -version=v0 z02.d
z02.d(47): Error: static assert  "can't call method 'foo' in type 
S"
z02.d(55):        instantiated from here: doit!("foo", 
CallAllowed0, S, int)

% rdmd -version=v1 z02.d
foo(42)

% rdmd -version=v2 z02.d
foo()

% rdmd -version=v3 z02.d
z02.d(47): Error: static assert  "can't call method 'foo' in type 
S"
z02.d(61):        instantiated from here: doit!("foo", 
CallAllowed1, S)
Aug 11 2016