| |
 | Posted by Mike Parker in reply to CJS | Permalink Reply |
|
Mike Parker 
| 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
>
> }
|