In a library I was writing I was in need of the following:

Write code that takes a function pointer/delegate and an array of strings that calls the function by parsing each string into the given functions arguments. And if the function has a return value, the code will also return the functions return value after the call.

I had written this functionality before in .NET (C# specifically) using .NET's runtime reflection. The code looks nice but runtime reflection has poor performance. Using D's compile-time features I was able to write a D template function that implemented this in about 10 lines of code.

ReturnType!Function call(Function)(Function func, const char[][] args...) if (isCallable!Function)
{
  alias Args = ParameterTypeTuple!Function;

  if(args.length != Args.length)
throw new Exception(format("Expected %d arguments but got %d", Args.length, args.length));

  Args argsTuple;

  foreach(i,Arg;Args) {
    argsTuple[i] = to!Arg(args[i]);
  }

  return func(argsTuple);
}

Here's a unit test to demonstrate its usage:

unittest
{
  void voidFunction()
  {
    writeln("[Test] Called voidFunction()");
  }
  void randomFunction(int i, uint u, string s, char c)
  {
writefln("[Test] Called randomFunction(%s, %s, \"%s\", '%s')", i, u, s, c);
  }
  ulong echoUlong(ulong value)
  {
    writefln("[Test] Called echoUlong(%s)", value);
    return value;
  }

 (&voidFunction).call();
 (&randomFunction).call("-1000", "567", "HelloWorld!", "?");

  string passedValue = "123456789";
  ulong returnValue = (&echoUlong).call(passedValue);
  writefln("[Test] echoUlong(%s) = %s", passedValue, returnValue);

  try {
    (&randomFunction).call("wrong number of args");
    assert(0);
  } catch(Exception e) {
    writefln("[Test] Caught %s: '%s'", typeid(e), e.msg);
  }

  writeln("[Test] Success");
}

I think this challenge does a great job in demonstrating D's compile-time power. I couldn't think of a way to do this in C without doing some type of code generation. The reason I needed this functionality was because I was writing a remote procedure call type of library, where the function's being called were known at compile time, but the arguments (passed over a socket) had to be processed at runtime. I was wondering if anyone had good solutions to this problem in other languages. I was very pleased with the D solution but I predict that solutions in other languages are going to be much uglier.

Reply via email to