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.

Reply via email to