Those who worked enough with C or other procedure oriented languages know how much flexibility callbacks provide. The simplest example is the qsort function of the C standard library. It is also not unintentional that many libraries, windowing system APIs and operating system APIs also highly rely on callbacks to pass a particular task over to another program module and it is one of the fundamental tools needed to implement an event-driven application. At the same time, object oriented languages does not directly support the concept of callbacks as they don’t really fit into the paradigms used by these languages. Fortunately, even if not as a language feature, all object oriented languages support a similar facility like callbacks in the form of delegates.

Delegation as a design pattern is used to describe the situation when one object passes on the implementation of a particular task to another object. This clearly reflects the purpose of callbacks used in procedure oriented languages. Many languages does natively support some form of delegation, some of the well known ones are C# and Delphi.

Callbacks

As mentioned before, the facility present in procedure oriented languages that enables the delegation of functionalities to other modules is done with callbacks. These callbacks are specified by passing function pointers to some registration functions provided by the library. Here is a very simple C example:

/* server header */
void registerFooCallback(int (*fooCB)(int, float));
int doFoo(int a, float b);

/* client code */
int myFooCallback(int a, float b) {
    /* ... do something ... */
}

int main() {
    registerFooCallback(myFooCallback);
    cout << doFoo(5, 3.2f);
    return 0;
}

Here we can see how easily callbacks provide injection of user code for handling events happened in the server.

Delegation as a design pattern

The simplest way to create object oriented callbacks is by applying the design pattern of delegation. If we would like to construct the C++ equivalent of the example above using the mentioned pattern, we end up with something like the following:

/* server header */
class IFooCallback {
public:
    virtual int operator() (int a, float b) = 0;
};

class Foo {
private:
    IFooCallback* _fooCB;
public:
    void registerCallback(IFooCallback* fooCB);
    int doFoo(int a, float b);
};

/* client code */
class MyFooCallback: public IFooCallback {
    int operator() (int a, float b) {
        /* ... do something ... */
    }
};

int main() {
    Foo foo;
    MyFooCallback fooCB;
    foo.registerCallback(fooCB);
    cout << foo.doFoo(5, 3.2f);
    return 0;
}

As you can see, it is quite straightforward to provide an object oriented alternative to callbacks. However, there is a very significant drawback when using the technique above, namely the type intrusion inherently coming from this definition of a callback. The client code needs to explicitly inherit it’s own code from a type defined in the server. This results in tight coupling and is likely to carry other disadvantages inside regarding to maintainability and migration issues.

Delegate methods

In our previous attempt to provide an easy to use C++ alternative for callbacks with OOP in mind we tried to replace function pointers with a pure virtual base class that acts like an interface definition for our callback. However, it somewhat violates the original goals of delegates which by definition should be some form of run-time inheritance (this varies from definition to definition, still, this is the one that I’m referring to in this article). We soon figure out that the most convenient way would be to be able to assign member functions of any class as a callback. Obviously, the parameters and return type should still match as previously to provide type safety, but we would like to remove any additional dependencies between the client and the server.

While C++ does have the term of pointers to member functions there is no easy and standard way to implement callbacks using them. Or is there? First of all, there is no particular problem with class static member functions as they are much like C functions, however, limiting delegates to static methods heavily affects the freedom of the developer. The problem with object member functions and especially with virtual member functions is that they have the implicit parameter this that enables them to access the object they correspond to.

The popular Boost library provides mechanisms that enables the use of object member functions as separate entities by using the bind functor adaptor which became part of the language standard as part of Technical Report 1. This extension makes it possible to use member functions as delegates in a way that does not involve any type intrusion side effects.

Unfortunately, these facilities involve a noticeable performance hit when the callback is invoked compared to simple method invocations. Also, using functor adaptors for implementing delegates is not the most straightforward and makes the code quite ugly compared to an ideal situation when delegates are part of the language itself. Of course, this is only my opinion, others who used these libraries more often may have a different vision about the topic.

Anyway, as for me performance is always a concern, I started to look around for alternatives. It surprised me that I’ve found even two of them very soon:

  • Fastest Possible C++ Delegates by Don Clugston – This is a library that provides delegates that are as fast as simple virtual method invocations. The implementation strongly relies on the behavior of different compilers, yet is very portable, at least as far as I can tell.
  • The Impossibly Fast C++ Delegates by Sergey Ryazanov – This library was introduced as an alternative to the previous one that strictly relies only on standard features of the languages. Surprisingly, this later is less supported by different compiler implementations and it is also somewhat slower than the previous one.

Personally, I go with the first one as for me performance and portability is more important than conformance with the standard. And, of course, it is not that hard to change the back-end for the delegate support at some time if I change my mind. Finally, lets see how our foo callback looks like when using the fast delegates of Don Clugston:

/* server header */
class Foo {
private:
    FastDelegate2<int, float, int> _fooCB;
public:
    void registerCallback(FastDelegate2<int, float, int> fooCB);
    int doFoo(int a, float b);
};

/* client code */
class MyClass {
    virtual int handleFoo(int a, float b) {
        /* ... do something ... */
    }
};

int main() {
    Foo foo;
    MyClass myObj;
    foo.registerCallback( MakeDelegate(&myObj, &MyClass::handleFoo) );
    cout << foo.doFoo(5, 3.2f);
    return 0;
}

Multicast delegates

The delegates presented previously can only be bound to a single method, as usually delegates behave this way, although a single method can be bound by many delegates. The signals and slots model extends this to a many-to-many relationship. Thus a signal is actually just a delegate that can bind to multiple methods at once. Such a primitive is sometimes also referred to as a multicast delegate.

Multicast delegates come handy especially in case of user interface programming and other situations where the event based programming model is used. The basic foundation behind this programming model is the idea of “subscribe and notify”. That means there are publishers who will do some logic and sometimes publish events. When such an event is published, it is actually sent out to the subscribers who have subscribed to receive the specific event. At implementation level this is nothing more than having a multicast delegate in the publisher object and providing an interface that will be used by the subscriber objects to register one of their methods that has to be called in case a particular event occurs.

There are plenty of signals and slots libraries out there including but not limited to the Boost Signals library. However, again, if performance is a concern one must look around carefully to find the appropriate library suitable for a particular purpose. One such library that extends the fast delegates of Clugston with a signals and slots framework is that of Patrick Hogan‘s.

Asynchronous delegates

If we do one more step forward, we arrive to asynchronous delegates that can provide us a flexible yet efficient messaging system for multi-threaded applications. The only additional thing we have to implement a message queue on the callee side and optionally some form of synchronization if we would like to also make it possible for the asynchronous delegates to return data to the caller.

As this topic deserves a thorough discussion on its own, I would recap on the subject in a future article and try to provide a sample implementation using OpenMP as usual.

Conclusion

We’ve just touched the surface of what possible use case scenarios of delegates one can met during software development, still, we’ve seen how many advantages such a programming primitive can give to C++ developers no matter if they are implementing a very simple library of sorting algorithms like the qsort C standard library function or a robust, fully event-driven multi-threaded application. We’ve also seen that there exist several efficient implementations of such a framework for those performance fanatics like me.

It is a perfect example how easily one can extend C++ with another facility that is usually available only in the most modern managed languages. By the way, I would be interested in your opinion what do you like the most in other languages like Java and C#, and you are disappointed that C++ does not directly provide the same thing. Maybe there exists a C++ alternative for those facilities as well, just we have to look around to find them…