Thread overview
Retreive method given object, name and arguments
Aug 11, 2016
Michael Coulombe
Aug 11, 2016
Lodovico Giaretta
Aug 11, 2016
ketmar
Aug 11, 2016
ketmar
Aug 11, 2016
ketmar
August 11, 2016
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.
August 11, 2016
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);");
}
August 11, 2016
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.
August 11, 2016
On Thursday, 11 August 2016 at 20:41:33 UTC, ketmar wrote:
ah, my bad, i missed UDA part of the question. sorry. ;-)
August 11, 2016
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)