On Thursday, 4 July 2013 at 06:43:12 UTC, CJS wrote:

In my case I'm trying to figure out the best way to pass functions to other fundtions. So I wrote the following toy code to see what the compiler would do. I'm trying to understand why the compiler emitted errors on the code below (shown w/ comments). Any insight/suggestions on better ways to pass functions around would also be appreciated.

First, to clarify some terminology.

This is a function that takes a delegate as a parameter.
void f(int delegate(int) h){
    writefln("h(0)=%d", h(0));
}

This is a function that takes a function *pointer*, not a function, as a parameter.
void g(int function (int) h){
    writefln("h(0)=%d", h(0));
}


This one is an inner function.
    int foo(int a){ return a+6;}

And this is a function literal which, in essence, is a function pointer.
    auto bah = function int(int b){ return b+7;};

In D, functions are not first class objects as they are in some other languages, so you can't actually pass them around. But what you can pass around is a pointer to a function. Try this.

void g(int function (int) h) {
    writefln("h(0)=%d", h(0));
}

void gg( int i ) { return i + 6; }

void main() { g( &gg ); }

Here, I'm passing a function pointer to g, which is exactly what it wants.

In your code, g(bah) succeeds because when the compiler encounters a function literal, it creates a function somewhere and stores a pointer where you assign it. So your bah is a function pointer. Hence g(bah) succeeds. g(&bah) fails because &bah makes it a pointer to a function pointer, which is not the kind of parameter that g accepts.

Delegates and function pointers are quite similar in usage, but architecturally different. A function pointer consists of one thing, a pointer to a function. A delegate has a pointer to a function *and* a reference to the stack frame from whence it came. There are three ways to create a delegate: via a delegate literal, via taking a pointer to a class method, or via taking a pointer to an inner method. Consider this:

void main() {
   int i = 10;
   int foo( int a ) {
      i = a + 6;
      return i;
   }
   f( &foo );
   writeln( i );

   int j;
}

Because a delegate can reference the stackframe where it was created, you can use them to modify variables inside a function or to modify class member variables. Delegates declared inside a function can only modify variables declared before the inner function or delegate literal. So in my example above, foo can modify i, but trying to modify j will be a compiler error.

So f(foo) fails because just 'foo' doesn't do anything. A function can be called like foo(), or a pointer can be taken with &foo, but just 'foo' is meaningless. f(&foo) succeeds because taking a pointer to an inner function creates a delegate. f(bah) fails because bah is a function pointer and not a delegate. f(&bah) fails because &bah is a pointer to a function pointer. You should now also understand why g(foo) and g(&foo) fail as well.


    f(foo); //error
    f(&foo);
    f(bah); //error
    f(&bah); // error

    g(foo); //error
    g(&foo); //error
    g(bah);
    g(&bah); //error

}

Reply via email to