digitalmars.D - Function Pointer Challenge
- Jonathan Marler (64/64) Apr 16 2014 In a library I was writing I was in need of the following:
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