Wednesday, September 24, 2008

Callbacks, the trick pointer you execute

At work I tend to develop programs using C#, which I don't particularly like but it does have some neat features. One of the features that caught my attention are delegates. Delegates are essentially function pointers (actually they do a little more than that). A function pointer is just a pointer to a function much like a pointer to a variable. I found it extremely interesting how delegates are used in ASP .NET for event driven processes.

I began wondering if I could implement similar systems in my own projects using C++.

Callbacks in C++ provide a way to call functions by executing function pointers. In C# delegates are type safe, this helps ensure you don't end up passing and receiving junk data to and from your function. Callbacks are not quite as nice, they are not necessarily typed and usually make heavy use of void pointers and unsafe type casting. To achieve typed callbacks in C++ I started making a templated callback class that allows for typed arguments and typed returns. Using a templated library helps ensure type safety and provides excellent code reuse when using callbacks with various types. Using the templated callback library, making a callback is as easy as...

void myFunction(int x)

Callback1<int> myCallback( myFunction );

Executing the callback is then as simple as


Why would we want to go through all this trouble just to run myFunction? Well, think about a system that executes functions but the functions are not known until runtime. Event processing tends to be one such system.

For event processing you could have a function that contains one giant if else or case statement for every possible event. Or you could make a system where you register functions with a type of event, and when the specific event occurs, a callback to your function is executed. This type of event system is exactly what I used callbacks for.

In the Stepmania Online game server I am developing, players are able to enter commands from the chat interface to manipulate the server. Since the events the server is handling are text strings, a switch statement is not an option. With a couple commands, multiple if else statements is an ok solution. However once the number of commands begins to grow, the if else statements become very long and ugly. To solve this I made a list of callbacks, each associated with a string command. I then "registered" each function with a string command by creating a callback to the function and adding it to the list along with the associated string command.

When a command is received, the program simply loops through the list of command stringsand callback. When a match is found between the stored string and the command, the callback associated with the command is executed. No giant if else statement required!

The real power in this system is that extra commands can be created by just compiling and linking in extra commands. This means, the game server could be released as a library and the chat commands can be expand uppon without touching or recompiling the core of the server. Very useful!

I have found that it takes a while to fully grasp the concept of callbacks, but it is well worth the effort.

No comments:

Post a Comment