phoenix::Tutorial - Callbacks

phoenix uses nall::function to handle the binding of callback functions. The reason I have chosen to use my own function template class is because of syntax limitations in std::function. Most notably, binding a member function callback is a pain in the ass with std::function. The mixture of std::bind, std::memfn, etc is seriously convoluted.

phoenix allows you to bind just about anything: global function, static member functions, non-static member functions, functors (objects with operator()) and lambdas both with and without closures.

phoenix function objects are also copyable, empty-testable, and resettable.

Here are some usage examples:

Button button;
button.onActivate = &global_function_callback;
button.onActivate = &Class::static_function_callback;
button.onActivate = { &Class::member_function_callback, &classObject };
button.onActivate = functor_callback;
button.onActivate = []() { lambda_expression; };
button.onActivate = [this, &x]() { this->lambda_closure_expression(x); };
window.onClose = button.onActivate = []() { OS::quit(); };

Many toolkits create "interesting" possibilities, due to poor handling of when to invoke callbacks. For instance, in Qt, if you toggle the check state of a QTreeWidgetItem, it will invoke the QTreeWidget itemChanged callback. Now let's say that you perform a large amount of code in response to this, and you also have code that sets all checkboxes in the control to unchecked. With Qt, your callback will be invoked every single time.

But it's not consistent! Setting the text of a QTextEdit will not call the textChanged() callback. So you never know what to expect. Now imagine if your callback programmatically adjusted something that invoked the callback again. You could get stuck in an infinitely recursive loop, causing a stack overflow and thus application crash.

phoenix ensures that callbacks are only executed in response to user-initiated actions. Anything you do programmatically will not invoke one of your callbacks. You will never get stuck in an infinite loop in this way. Of course, sometimes you want to invoke your callbacks in response to programmed actions. Not a problem, simply call the callbacks after you are finished. You can manually invoke a nall::function callback, just as if it were a regular control:

button.onActivate();

You can even test to ensure that a callback has been assigned, prior to calling it, if you are not sure:

if(button.onActivate) button.onActivate();