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.