Passing a function as an argument to another function : what is this sorcery ?

Gary Willoughby via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun May 25 03:18:35 PDT 2014


On Sunday, 25 May 2014 at 09:37:46 UTC, Derix wrote:
> Hello everyone,
>
> So I'm "Getting Started With Gtkd" [1] and the tuto includes 
> this
> piece of code :
>
> ...
>
>        DrawingArea da = new DrawingArea(590, 200);
>        da.addOnDraw(&onDraw);
>        layout.put(da, 5, 30);
>
>        add(layout);  // Add the layout to our main window
>        showAll();
>     }
>
>     bool onDraw(Context c, Widget w)
>     {
>        //draw things
>        return true;
>     }
> }
>
> and I'm a bit puzzled by the line
>        da.addOnDraw(&onDraw);
>
> I'm pretty sure I've met this construct before along with
> relevant explainations, but I find myself a bit forgetful and in
> need of a refresher. Hence questions :
>
> 1) What is the generic name for this kind construct ?
>
> 2) Any hint to some reading about the supporting theory or
> rationale ?

It's basically passing an existing function via a pointer. Notice 
the ampersand (&)? That gets the underlying memory location (i.e. 
pointer). Normal procedural type functions can be passed like 
this as can methods of classes (if you have access to them). When 
passing a class method like this it can be referred to as passing 
a delegate. Delegates internally store another pointer to it's 
surrounding context.

For example, a function can be passed like this:

void foo()
{
     // Do something.
}

bar.addFoo(&foo);

Then in the addFoo method foo can be called as if it was a normal 
function. You can also write the above like this:

bar.addFoo(function(){
     // Do something.
});

As function literals are passed via a pointer by default so no 
ampersand needed.

The problem is that normal functions can not refer to anything 
outside of their scope. For this you need a delegate which 
contains a context pointer (which is a reference to it's 
surroundings). Here is an example if using a class method.

class Foo
{
     public void bar()
     {
         // Do something.
     }

     public void baz()
     {
         // Refers to bar outside of this method's scope.
         this.bar();
     }
}

auto foo = new Foo();

// baz can refer to the instance of Foo (it's context)
// so it can call bar.
qux.addBaz(&foo.baz);

You can also use the literal notation too:

qux.addBaz(delegate(){
     // I can now use things outside this scope.
});

Like function literals, delegates are also passed by their 
pointer by default.
>
> 3) When the onDraw function is actually called, whence does it
> takes its arguments from ? What is that Context ? Does it float
> around as some sort of implicit global object ? When was it
> instanciated ?

When passing functions or methods like this they need to be typed 
just like anything else you would pass as an argument. Like this:

alias void delegate(string) MyCallback;

Here we define the signature of a delegate using an alias. Once a 
method is defined taking this alias as a type then it will only 
accept a delegate with this signature.

class Foo
{
     // Only accept 'void delegate(string)'
     void bar(MyCallback baz)
     {
         // call conforming to the MyCallback signature.
         baz("hello world"); <--
     }
}

auto foo = new Foo();

// Passed delegate conforms to the MyCallback signature.
foo.bar(delegate(string x){
     writeln(x);
});

Functions are typed the same way:

alias void function(string) MyCallback;

> 4) Is &onDraw a predefined event belonging to the class
> DrawingArea ? Is the name of the onDraw function thus 
> constrained
> ?

onDraw will just be a method that accepts a delegate (or standard 
function).

> 5) What is the chain of events leading to the "onDraw" event
> occuring ? I'd guess it's the 'showAll()' line, but by the way
> where does this 'showAll()' come from ? In the documentation

I've no idea you'll have to read the source to find that out.

> I don't see it as a method belonging to the class DrawingArea. 
> Is
> it inherited from a superclass ?

Probably.


More information about the Digitalmars-d-learn mailing list