how to call a function passed as argument with its parameters already given in D?

Viewed 176

I need to call a function passed as argument to another function and it must be passed its needed arguments firstly. In c++, this problem is solved with a macro:

#include <iostream>

#define CALL(x) x; \
                std::cout << "Called!" << std::endl;

void foo(int a, int b)
{
    std::cout << a * b << std::endl;
}

int main()
{
    CALL(foo(9, 8)); // I want to pass 2 int parameters inside 'foo' function call
    system("PAUSE");
}

It sould output:

> 72
> Called!

That is exactly how I need to call the function in D. Any ideas?

Edit: I need this to be done in D. I want to call "foo" inside CALL like:

CALL(foo(9, 8)) // and not like: CALL(foo, 9, 8)

But I don't know how this is achieved in D. Perhaps with a mixin?

1 Answers

In D, you can use a lazy function parameter for this.

import std.stdio;

void CALL(lazy void x) {
        writeln("before called");
        x;
        writeln("after called");
}

void foo(int x, int y) {
        writeln(x, " ", y);
}

void main() {
        CALL(foo(3, 5));
}

D's lazy parameter storage class causes the compiler to wrap whatever you give it in a little anonymous function. The above is as if you wrote:

import std.stdio;

void CALL(void delegate() x) { // note delegate here in long-form syntax
        writeln("before called");
        x();
        writeln("after called");
}

void foo(int x, int y) {
        writeln(x, " ", y);
}

void main() {
        // and this delegate too
        CALL( delegate() { return foo(3, 5); } );
}

But the compiler rewrites it for you. This is why I said lazy void - the void there is the return type of the hidden function you pass. If it returned int, you could use lazy int instead.

Note that since x inside the CALL function is rewritten to be a hidden function, calling it twice will actually evaluate the arguments twice:

void CALL(lazy void x) {
        writeln("before called");
        x;
        writeln("after called");
        x;
        writeln("after called again");
}

would do:

before called
3 5
after called
3 5
after called again

Notice how it printed out the arguments twice. Just like the C macro, actually. But if that's not what you want, simply assign it to a temporary yourself:

void CALL(lazy int x) {
    auto tmp = x;
    // you can now use tmp as a plain int
}
Related