Callback system in D

We’ve been evaluating D for use in Daydream, and I decided to see how easy it would be to create a callback system in the D  language (aka events or signals). This is a daunting task in C++ because C++ templates can only accept a static number of arguments… very bad when you have a function that can accept any number of arguments. To solve this problem in C++ you need to create a separate template for each number of possible arguments.

In D you can create templates that accept any number of arguments! You can treat these as a tuple, an array, or use them with tail recursion (à la PROLOG).

Combine this with the natural awesomeness of D and you’re setup for a power punch. Following this text is a very simple callback system in D.
A short but sweet 50 lines of code; it stores both functions and delegates and gives you a good launching point to create a more complicated call back system.


// Converts a function to a delegate. Stolen from
// Note that it doesn’t handle ref or out though
R delegate(T) toDg(R, T…)(R function(T) fp) {
struct dg {
R opCall(T t) {
return (cast(R function(T)) this) (t);
R delegate(T) t;
t.ptr = fp;
t.funcptr = &dg.opCall;
return t;

class SimpleCallback(R, P…)
alias R delegate(P) callbacktype;
alias R function(P) function_callbacktype;

private callbacktype[] callback_list;

typeof( this ) opCatAssign( in callbacktype callback )
callback_list ~= callback;
return this;

typeof( this ) opCatAssign( in function_callbacktype callback )
auto dg = toDg!(R, P)( callback );
return this ~= dg;

R emit( P p )
static if ( !is( R == void ) )
R last;

foreach( callback; callback_list )
static if ( !is( R == void ) )
last = callback( p );
callback( p );

static if ( !is( R == void ) )
return last;

alias emit opCall;

Here’s some example code:

[cc_d]SimpleCallback!( void ) sc = new SimpleCallback!( void );
SimpleCallback!( bool, char[] ) sc2 = new SimpleCallback!( bool, char[] );
sc ~= function void() { Stdout.formatln( “#1” ); };
sc ~= function void() { Stdout.formatln( “#2” ); };
sc2 ~= function bool( char[] str ) { Stdout.formatln( “#1 called with {}, returning false”, str ); return false; };
sc2 ~= function bool( char[] str ) { Stdout.formatln( “#2 called with {}, returning true”, str ); return true; };
Stdout.formatln( “Last sc2 callback returned {}”, sc2( “coffee” ) );[/cc_d]
And here’s the output:
#1 called with coffee, returning false
#2 called with coffee, returning true
Last sc2 callback returned true[/cc_text]

2 thoughts on “Callback system in D”

Leave a Reply

Your email address will not be published. Required fields are marked *