www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Function name

reply bearophile <bearophileHUGS lycos.com> writes:
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
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
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
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
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
parent "Adam D. Ruppe" <destructionator gmail.com> writes:
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
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 4/23/10 02:14, Adam D. Ruppe wrote:
 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?
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).
Apr 23 2010
parent "Adam D. Ruppe" <destructionator gmail.com> writes:
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
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
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,
 bearophile
I think http://www.dsource.org/projects/flectioned is what you are looking for. Don't know if it still works though.
Apr 23 2010
parent bearophile <bearophileHUGS lycos.com> writes:
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