www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Call function by its string name

reply "aldanor" <i.s.smirnov gmail.com> writes:
I was wondering if it was possible to call D functions by their 
names (strings that are not known at compile time) and couldn't 
find the answer anywhere in the documentation. Kinda like we can 
instantiate objects with Object.factory, would it be possible to 
somehow do the same with module-level functions? Or maybe with 
non-static class methods?
Oct 19 2013
next sibling parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Saturday, 19 October 2013 at 16:33:11 UTC, aldanor wrote:
 I was wondering if it was possible to call D functions by their 
 names (strings that are not known at compile time) and couldn't 
 find the answer anywhere in the documentation. Kinda like we 
 can instantiate objects with Object.factory, would it be 
 possible to somehow do the same with module-level functions? Or 
 maybe with non-static class methods?
You could make an associative array of function pointers with strings as keys. Probably not the best solution but it should work.
Oct 19 2013
parent reply "aldanor" <i.s.smirnov gmail.com> writes:
On Saturday, 19 October 2013 at 16:56:50 UTC, John Colvin wrote:
 On Saturday, 19 October 2013 at 16:33:11 UTC, aldanor wrote:
 I was wondering if it was possible to call D functions by 
 their names (strings that are not known at compile time) and 
 couldn't find the answer anywhere in the documentation. Kinda 
 like we can instantiate objects with Object.factory, would it 
 be possible to somehow do the same with module-level 
 functions? Or maybe with non-static class methods?
You could make an associative array of function pointers with strings as keys. Probably not the best solution but it should work.
Thanks for the reply, this is something I thought about of course. But what if I have hundreds of functions to dispatch to? The current (C) implementation does exactly that, autogenerates a sort of an associative array, but that's very ugly and requires an extra preprocessing step. I was thinking runtime reflections can help do this, but I'm not quite sure where to start (and there is also the performance question).
Oct 19 2013
next sibling parent reply "Meta" <jared771 gmail.com> writes:
On Saturday, 19 October 2013 at 17:17:47 UTC, aldanor wrote:
 On Saturday, 19 October 2013 at 16:56:50 UTC, John Colvin wrote:
 On Saturday, 19 October 2013 at 16:33:11 UTC, aldanor wrote:
 I was wondering if it was possible to call D functions by 
 their names (strings that are not known at compile time) and 
 couldn't find the answer anywhere in the documentation. Kinda 
 like we can instantiate objects with Object.factory, would it 
 be possible to somehow do the same with module-level 
 functions? Or maybe with non-static class methods?
You could make an associative array of function pointers with strings as keys. Probably not the best solution but it should work.
Thanks for the reply, this is something I thought about of course. But what if I have hundreds of functions to dispatch to? The current (C) implementation does exactly that, autogenerates a sort of an associative array, but that's very ugly and requires an extra preprocessing step. I was thinking runtime reflections can help do this, but I'm not quite sure where to start (and there is also the performance question).
What about mixins?
Oct 19 2013
parent reply "aldanor" <i.s.smirnov gmail.com> writes:
On Saturday, 19 October 2013 at 17:19:25 UTC, Meta wrote:
 On Saturday, 19 October 2013 at 17:17:47 UTC, aldanor wrote:
 On Saturday, 19 October 2013 at 16:56:50 UTC, John Colvin 
 wrote:
 On Saturday, 19 October 2013 at 16:33:11 UTC, aldanor wrote:
 I was wondering if it was possible to call D functions by 
 their names (strings that are not known at compile time) and 
 couldn't find the answer anywhere in the documentation. 
 Kinda like we can instantiate objects with Object.factory, 
 would it be possible to somehow do the same with 
 module-level functions? Or maybe with non-static class 
 methods?
You could make an associative array of function pointers with strings as keys. Probably not the best solution but it should work.
Thanks for the reply, this is something I thought about of course. But what if I have hundreds of functions to dispatch to? The current (C) implementation does exactly that, autogenerates a sort of an associative array, but that's very ugly and requires an extra preprocessing step. I was thinking runtime reflections can help do this, but I'm not quite sure where to start (and there is also the performance question).
What about mixins?
But the function/method names are only known in runtime (dispatched by user input parser), so mixins wouldn't really help, or am I missing something?
Oct 19 2013
parent "Meta" <jared771 gmail.com> writes:
On Saturday, 19 October 2013 at 17:28:44 UTC, aldanor wrote:
 But the function/method names are only known in runtime 
 (dispatched by user input parser), so mixins wouldn't really 
 help, or am I missing something?
Sorry, I misread and thought you said the strings *were* known at compile time.
Oct 19 2013
prev sibling parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Saturday, 19 October 2013 at 17:17:47 UTC, aldanor wrote:
 On Saturday, 19 October 2013 at 16:56:50 UTC, John Colvin wrote:
 On Saturday, 19 October 2013 at 16:33:11 UTC, aldanor wrote:
 I was wondering if it was possible to call D functions by 
 their names (strings that are not known at compile time) and 
 couldn't find the answer anywhere in the documentation. Kinda 
 like we can instantiate objects with Object.factory, would it 
 be possible to somehow do the same with module-level 
 functions? Or maybe with non-static class methods?
You could make an associative array of function pointers with strings as keys. Probably not the best solution but it should work.
Thanks for the reply, this is something I thought about of course. But what if I have hundreds of functions to dispatch to? The current (C) implementation does exactly that, autogenerates a sort of an associative array, but that's very ugly and requires an extra preprocessing step. I was thinking runtime reflections can help do this, but I'm not quite sure where to start (and there is also the performance question).
No matter what happens, if you want to take a runtime string and work out what function it corresponds to then you're going to have to use some sort of string matching. Unless you have a very specific function name format then a hash is probably the fastest way to do this, especially in the case of hundreds of functions. D's compile-time reflection could probably make building the associative array neat and easy.
Oct 19 2013
parent reply "aldanor" <i.s.smirnov gmail.com> writes:
On Saturday, 19 October 2013 at 17:35:53 UTC, John Colvin wrote:
 On Saturday, 19 October 2013 at 17:17:47 UTC, aldanor wrote:
 On Saturday, 19 October 2013 at 16:56:50 UTC, John Colvin 
 wrote:
 On Saturday, 19 October 2013 at 16:33:11 UTC, aldanor wrote:
 I was wondering if it was possible to call D functions by 
 their names (strings that are not known at compile time) and 
 couldn't find the answer anywhere in the documentation. 
 Kinda like we can instantiate objects with Object.factory, 
 would it be possible to somehow do the same with 
 module-level functions? Or maybe with non-static class 
 methods?
You could make an associative array of function pointers with strings as keys. Probably not the best solution but it should work.
Thanks for the reply, this is something I thought about of course. But what if I have hundreds of functions to dispatch to? The current (C) implementation does exactly that, autogenerates a sort of an associative array, but that's very ugly and requires an extra preprocessing step. I was thinking runtime reflections can help do this, but I'm not quite sure where to start (and there is also the performance question).
No matter what happens, if you want to take a runtime string and work out what function it corresponds to then you're going to have to use some sort of string matching. Unless you have a very specific function name format then a hash is probably the fastest way to do this, especially in the case of hundreds of functions. D's compile-time reflection could probably make building the associative array neat and easy.
Yes, in my case it's very specific, let's say I receive a string "fun" and want to call do_fun(args) or Obj.do_fun(args). Thanks, I'll try looking into compile-time reflection.
Oct 19 2013
parent reply Kenji Hara <k.hara.pg gmail.com> writes:
A quick sample code to make a table of function pointers at compiler time.

module test;
import std.typetuple;

// calculate compile-time tuple of functions declared in 'mod' module
template getFunctions(alias mod)
{
    template filterPred(string name)
    {
        // if the 'name' is really a function, returns true
        enum filterPred = is(typeof(__traits(getMember, mod, name)) ==
function);
    }
    alias names = Filter!(filterPred, __traits(allMembers, mod));

    template mapPred(string name)
    {
        alias mapPred = TypeTuple!(__traits(getMember, mod, name))[0];
    }
    alias getFunctions = staticMap!(mapPred, names);
}

// gather functions from modname, then make function pointer table
auto makeTable(alias modname)()
{
    mixin("import "~modname~";");
    mixin("alias funcs = getFunctions!("~modname~");");

    immutable(void*)[] make(size_t n)()
    {
        static if (n < funcs.length)
            return cast(immutable(void*))&(funcs[n]) ~ make!(n+1)();
        else
            return [];
    }
    immutable(void*)[funcs.length] tbl = make!0()[0 .. funcs.length];
    return tbl;
}

// make function pointer table
immutable func_table = makeTable!"decl"();

void main()
{
    (cast(void function())func_table[0])();
    assert((cast(int function(int))func_table[1])(10) == 20);
}

module decl;
void fn() { import std.stdio; writeln("call fn"); }
int bar(int n) { import std.stdio; writeln("call bar"); return n * 2; }

----

$ dmd decl.d -run test
call fn
call bar

There's no runtime cost to make function pointer table.

Kenji Hara


2013/10/20 aldanor <i.s.smirnov gmail.com>
 Yes, in my case it's very specific, let's say I receive a string "fun" and
 want to call do_fun(args) or Obj.do_fun(args). Thanks, I'll try looking
 into compile-time reflection.
Oct 19 2013
parent "aldanor" <i.s.smirnov gmail.com> writes:
On Saturday, 19 October 2013 at 17:58:36 UTC, Kenji Hara wrote:
 A quick sample code to make a table of function pointers at 
 compiler time.
That looks like exactly the kind of D-fu that I need, great example, thanks Kenji!
Oct 19 2013
prev sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 10/19/13 18:33, aldanor wrote:
 I was wondering if it was possible to call D functions by their names (strings
that are not known at compile time) and couldn't find the answer anywhere in
the documentation. Kinda like we can instantiate objects with Object.factory,
would it be possible to somehow do the same with module-level functions? Or
maybe with non-static class methods?
You can build a name->funcPtr table at CT and look up at RT. You could also let the dynamic linker handle it, but that approach will be less portable. For example, this will work in linux: ========================================================================== // gdc dlopen1.d -o dlopen1 -ldl -Wl,--export-dynamic && ./dlopen1 f1 2 import std.stdio; alias int function(int) FT; int dummy42(int a); int f1(int a) { int i = 42+a; writeln(i); return i; } int f2(int a) { int i = 17*a; writeln(i); return i; } int main(string[] argv) { import std.conv, std.array; auto mnamehack = replace(dummy42.mangleof, "7dummy42", to!string(argv[1].length)~argv[1])~"\0"; auto fp = cast(FT)dlsym(RTLD_DEFAULT, mnamehack.ptr); if (!fp) { writeln(to!string(dlerror())); return 1; } return fp(to!int(argv[2])); } extern (C) void* dlsym(const void* handle, const char* symbol); extern (C) const(char)* dlerror(); enum RTLD_DEFAULT = null; ========================================================================== Of course this is just an example - the name mangling is hack (maybe there is something in druntime/phobos that could help), but enough for many cases where you just want to choose from a known set of functions/methods at RT. artur
Oct 19 2013