Vala delegates under the hood

On the Vala mailing list someone wondered if delegates are merely function pointers, not some higher-level concept.  This was in the context of a blog post earlier this year speculating (accusing?) Vala of infringing on Microsoft patents.  I won’t step into the legal morass of software patents under United States law, but it’s important to know: delegates are not merely function pointers.  Understanding how delegates differ from function pointers makes for a better understanding of their power.

Consider the common C++ dictum against taking pointers of non-static functions (that is, methods, which are different than pointers to member functions, C++’s mangled way of dealing with this problem).  A method pointer is near-useless without a corresponding this pointer (which must be manually passed on the stack).  And pointers to virtual methods bypass the vtable, which is itself dangerous for a bunch of reasons.

Delegates solve these problems in an elegant way.  In order to do this, a delegate bundles together a this pointer (which Vala calls the target and is null for a static delegate) and a function pointer.

However, the delegate’s function pointer is not merely pointing at your callback.  Instead, Vala passes a pointer to a hidden delegation function which calls the “real” function.  The delegation function re-sorts the callback’s parameters to move the user data pointer (which can be anywhere on the stack, and is often last in GLib) to the first parameter for the real callback (making it the this pointer).  If the delegate is for a virtual function, this “real” function in turn calls through the object’s vtable (which is a function pointer stored in the object’s instance structure).

These levels of indirection means delegates just work (with some notable exceptions).  Because this binding happens late (i.e. at run-time), you can pass delegates around in constructors before the child class has completed initialization (although there’s some danger there, obviously).  If Vala later adds deeper mixin support, late binding means delegates still work.

What’s cool about Vala is how this is all laid out visibly in C.  Perusing the C code makes it easy to learn how modern object-oriented features are implemented down at the metal.  In essence, Use the Source Luke has two meanings with Vala: you can glean language features by examining the compiler or the code the compiler generates.