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
}