www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Function Pointer Challenge

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.


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.
Apr 16 2014