5
votes

OK, so that's what I need :

  • Let's say we've got a string variable, e.g. func with some value, given by the user (not a constant)
  • How could we call a function which name is the value of func?

UPDATE:

Perhaps thought that what I needed was pretty self-explanatory, but since I'm noticing many downvotes, here you are :

string func = "myfunc";

I need something like call(func), which will call myfunc. Like PHP's call_user_func_array()


Any ideas?

I had a look at mixins but this doesn't look like what I'd need.


P.S. I'm tagging the question with c and c++ too, since a universal solution could be theoretically possible, given the similarities among the languages.

6
The best way I can interpret your question is "how to call a function with a parameter". Which would be, functionName(func). I guess this must not be what you're asking, so please clarify the question. - Vladimir Panteleev
@CyberShadow - I read it as "user enters a value into a string, that string is a function name, how do I call that function". - Mike
Make a hashtable of names => function pointers, look up the string in the table and call the result. - user3286380
Oh... in that case, good luck! Especially in C++ since the function names are mangled - Cory Kramer
check this answer stackoverflow.com/a/1118808/2549281 , but i guess it only work for C, and only for functions defined in your executable - Dabo

6 Answers

4
votes

Programming languages generally do not provide a way to access function names during runtime, as those names are usually stripped out by the linker, leaving behind only machine code.

As user3286380 suggested, one way to tackle this problem, which would work in all languages, is to make a table which cross-references function names and pointers to the respective functions. Then, your program can look up this table during run time.

If the language in question allows introspection (either run-time or compile-time), you can enumerate the functions in your module or program, and find the function whose name the user entered. In D, you can do this by using the allMembers trait on a module. This will give you an array of all declarations in the module; the next step would be to filter out functions, check that the function signature matches, then generate a switch statement which calls the respective function. You can use CTFE and string mixins to achieve the above.

1
votes

Create an array of pairs with the first element of each pair being the string function name and the second being the pointer to the function. Search the array and when the name is found, call it using the pointer. Note that Python has a dictionary class that enables you to do this as key:value pairs.

1
votes

I see 3 ways of doing that:

  • If you know in advance a collection of functions from which to choose, you could register an associative table of string -> functor where functor records both the function address and signature, something like std::function in C++

  • Otherwise, a more complex solution is to inspect the debug symbols of your own executable and build your table from that. You could also use pre-processors (like Qt's MOC) to build this table, or in the case of D use the builtin compile-time reflexivity.

  • If you really need flexibility use an interpreter instead of a compiler. Cling is a nice LLVM based C++ interpreter with just-in-time compilation.

1
votes

The only way I've ever done this before was to have the functions in your executable be linked to a string that "names" that function, then do a comparison.

I thought I would throw on a simple (1 function) example in C for you, I have to assume this works in D as well:

typedef struct {
    char * func_name;
    void (* fptr)();
} myS;

void print(){
    printf("hello world\n");
}

int main()
{ 
    myS Ex;
    char str[100] = "";

    // Obviously you can fill these in a more intelligent manner, use an array, etc
    Ex.func_name = malloc(strlen("print")+1);
    strcpy(Ex.func_name, "print");
    Ex.fptr = print;

    printf("Enter the function name\n");
    scanf("%99s", str);

    // and of course with a number of functions to examine you could use a switch
    if(!strcmp(str, Ex.func_name))
        Ex.fptr();
    else
        printf("Didn't find a function to call\n");

    return 0;
}
0
votes

The way I do is using associative arrays. An example would be:

module main;

import std.stdio;

class Tqfuncs{
private:
    void qwrite(string arg){
        write(arg);
    }
    void delegate(string)[string] pList;//store name & pointer to functions here
public:
    this(){
        pList = [
            "qwrite":&qwrite,//add the qwrite function
        ];
    }
    void call(string name, string arg){
        if (name in pList){
            pList[name](arg);//call the function
        }else{
            throw new Exception("unrecognized function call "~name);
        }
    }
}

void main(string[] args){
    Tqfuncs scrF = new Tqfuncs;
    scrF.call("qwrite","This will be written");
}

I've created a dynamic scripting language using this approach, you can know more using the source https://github.com/Nafees10/qscript .
However, there are some limits using this method:

  • All functions must be in a certain "format". Like I've used void functionName(string arg). But there is a workaround, if you're interested, you can check it in QScript (my project).
0
votes

No - you do not need that in a statically-typed language! Period.

Why? - Because the compiler can't know ahead the value (changed at runtime) of the variable holding the name of the function you want to run so when it encounters funcname(myvar) what machine code should it generate there?

Imagine for a second what you want works:

string funcname;
// here some initialisation code that modifies the funcname
int someVal = funcall(funcname);

What happens when the funcall() gets a name of a function that returns, say, an object Person (a user-defined type)??

Also, what happens when there is no function with name funcname?? A runtime error? No error? What?

What you want is in the domain of dynamic languages where type-safety is entirely ignored (which is unfortunately most of them).

HOWEVER... If your functions are all wrapped in a struct for an example, then D provides an elegant way of doing what you want through the forwarding (function dispatch). Read more about it here: https://dlang.org/spec/operatoroverloading.html#dispatch