digitalmars.D - Function name
- bearophile (32/32) Apr 22 2010 In Python I sometimes use the name of a given function reference (all la...
- Adam D. Ruppe (28/30) Apr 22 2010 How about this?
- bearophile (14/17) Apr 22 2010 If the sequence of functions is known at compile-time your solution can ...
- Adam D. Ruppe (12/16) Apr 22 2010 You could perhaps use it to create name/delegate pairs, which you use
- Jacob Carlborg (4/31) Apr 23 2010 Yes we still need classinfo, if you you store an object in a base class
- Adam D. Ruppe (5/8) Apr 23 2010 Ah, of course, that makes sense.
- Jacob Carlborg (3/35) Apr 23 2010 I think http://www.dsource.org/projects/flectioned is what you are
- bearophile (5/7) Apr 23 2010 Thank you for the link, I have forgotten about flectioned.
In Python I sometimes use the name of a given function reference (all lambdas are named "<lambda>"), this is a minimal example: def add(a, b): return a + b def mul(a, b): return a * b for func in [add, mul]: print func.__name__, func(10, 20) In D for object references it's easy to find the name at runtime: object_reference.classinfo.name But for functions the situation is less simple. Here are two ways I have found: import std.stdio: writeln; import std.typetuple: TypeTuple; import std.typecons: tuple; int add(int a, int b) { return a + b; } int mul(int a, int b) { return a * b; } void main() { // solution 1 foreach (name; TypeTuple!("add", "mul")) mixin(`writeln(name, " ", ` ~ name ~ `(10, 20));`); // solution 2 auto funcs = [tuple("add",&add), tuple("mul",&mul)]; foreach (ptr_name; funcs) writeln(ptr_name.field[0], " ", ptr_name.field[1](10, 20)); // hypothetical solution 3 auto funcs_ptr = [&add, &mul]; foreach (func; funcs_ptr) writeln(func.name, " ", func(10, 20)); } The first solution is not good because it uses a static foreach and I like to avoid messy string mixins when possible. The second solution is better, and I can use it, but it requires redundancy in those names that can cause bugs. The third solution is what I'd like to be able to write. To have such run-time reflection the compiler has to store in the binary a dictionary that maps function pointers and delegates to their names as strings (lambdas can be mapped to standard name). This can inflate the binary a little. This is not too much different from the data classes have, like their name that can be found with classinfo. What do you think? Bye, bearophile
Apr 22 2010
On Thu, Apr 22, 2010 at 07:48:31PM -0400, bearophile wrote:The third solution is what I'd like to be able to write.How about this? === import std.stdio; import std.traits; int add(int a, int b) { return a+b; } int mul(int a, int b) { return a*b; } auto funcwithName(T...)() { typeof(&T[0])[string] ret; foreach(t; T) ret[__traits(identifier, t)] = &t; return ret; } void main() { foreach(name, func; funcwithName!(add, mul)) { writefln("%s %d", name, func(10,20)); } } === $ ./funname mul 200 add 30 All the functions have to be the same type to loop over them like this, and it might not work with zero argument functions.This can inflate the binary a little. This is not too much different from the data classes have, like their name that can be found with classinfo.Btw, do we still need classinfo now that we have __traits? -- Adam D. Ruppe http://arsdnet.net
Apr 22 2010
Adam D. Ruppe:How about this?If the sequence of functions is known at compile-time your solution can be used, thank you. I have changed your function a little so it keeps the same order (in a hash iteration order is arbitrary): auto funcWithName(T...)() { Tuple!(string, typeof(&T[0]))[] result; foreach (t; T) result ~= tuple(__traits(identifier, t), &t); return result; }import std.traits;Why do you import std.traits?Btw, do we still need classinfo now that we have __traits?I think __traits is (mostly) for compile-time, while classinfo is run-time. (Surely there are ways to design a tidier compile-time and run-time reflection API). Bye, bearophile
Apr 22 2010
On Thu, Apr 22, 2010 at 08:38:39PM -0400, bearophile wrote:If the sequence of functions is known at compile-time your solution can be used, thank you.You could perhaps use it to create name/delegate pairs, which you use to build the other arrays later.Why do you import std.traits?Left over from my first attempt - I was going to use it to get the type of the functions, but instead just did typeof(&T[0]), then forgot to delete the import line.I think __traits is (mostly) for compile-time, while classinfo is run-time. (Surely there are ways to design a tidier compile-time and run-time reflection API).We can build runtime stuff out of the compile time stuff, in theory anyway. Daniel Ribeiro Maciel recently posted some runtime reflection code to the newsgroup, but I haven't had a chance to evaluate it yet. -- Adam D. Ruppe http://arsdnet.net
Apr 22 2010
On 4/23/10 02:14, Adam D. Ruppe wrote:On Thu, Apr 22, 2010 at 07:48:31PM -0400, bearophile wrote:Yes we still need classinfo, if you you store an object in a base class reference classinfo will give you the runtime type (the subclass) and __traits will give you the compile time type (the base class).The third solution is what I'd like to be able to write.How about this? === import std.stdio; import std.traits; int add(int a, int b) { return a+b; } int mul(int a, int b) { return a*b; } auto funcwithName(T...)() { typeof(&T[0])[string] ret; foreach(t; T) ret[__traits(identifier, t)] =&t; return ret; } void main() { foreach(name, func; funcwithName!(add, mul)) { writefln("%s %d", name, func(10,20)); } } === $ ./funname mul 200 add 30 All the functions have to be the same type to loop over them like this, and it might not work with zero argument functions.This can inflate the binary a little. This is not too much different from the data classes have, like their name that can be found with classinfo.Btw, do we still need classinfo now that we have __traits?
Apr 23 2010
On Fri, Apr 23, 2010 at 02:02:57PM +0200, Jacob Carlborg wrote:Yes we still need classinfo, if you you store an object in a base class reference classinfo will give you the runtime type (the subclass) and __traits will give you the compile time type (the base class).Ah, of course, that makes sense. -- Adam D. Ruppe http://arsdnet.net
Apr 23 2010
On 4/23/10 01:48, bearophile wrote:In Python I sometimes use the name of a given function reference (all lambdas are named "<lambda>"), this is a minimal example: def add(a, b): return a + b def mul(a, b): return a * b for func in [add, mul]: print func.__name__, func(10, 20) In D for object references it's easy to find the name at runtime: object_reference.classinfo.name But for functions the situation is less simple. Here are two ways I have found: import std.stdio: writeln; import std.typetuple: TypeTuple; import std.typecons: tuple; int add(int a, int b) { return a + b; } int mul(int a, int b) { return a * b; } void main() { // solution 1 foreach (name; TypeTuple!("add", "mul")) mixin(`writeln(name, " ", ` ~ name ~ `(10, 20));`); // solution 2 auto funcs = [tuple("add",&add), tuple("mul",&mul)]; foreach (ptr_name; funcs) writeln(ptr_name.field[0], " ", ptr_name.field[1](10, 20)); // hypothetical solution 3 auto funcs_ptr = [&add,&mul]; foreach (func; funcs_ptr) writeln(func.name, " ", func(10, 20)); } The first solution is not good because it uses a static foreach and I like to avoid messy string mixins when possible. The second solution is better, and I can use it, but it requires redundancy in those names that can cause bugs. The third solution is what I'd like to be able to write. To have such run-time reflection the compiler has to store in the binary a dictionary that maps function pointers and delegates to their names as strings (lambdas can be mapped to standard name). This can inflate the binary a little. This is not too much different from the data classes have, like their name that can be found with classinfo. What do you think? Bye, bearophileI think http://www.dsource.org/projects/flectioned is what you are looking for. Don't know if it still works though.
Apr 23 2010
Jacob Carlborg:I think http://www.dsource.org/projects/flectioned is what you are looking for. Don't know if it still works though.Thank you for the link, I have forgotten about flectioned. Some of those capabilities of flectioned are important enough to deserve to be inside Phobos2 (or inside the part of Tango2 designed to work attached to Phobos2). Bye, bearophile
Apr 23 2010