delegates, functions, and literals confusion

Mike Parker aldacron at gmail.com
Thu Jul 4 02:18:52 PDT 2013


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
>
> }



More information about the Digitalmars-d-learn mailing list