April 16, 2014 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. |
Copyright © 1999-2021 by the D Language Foundation