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.

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