Tag Archives: d

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.

[ccn_d]import tango.io.Stdout;

// Converts a function to a delegate. Stolen from http://dsource.org/projects/tango/ticket/1174
// 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 );
else
callback( p );
}

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

alias emit opCall;
}[/ccn_d]

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; };
sc();
Stdout.formatln( “Last sc2 callback returned {}”, sc2( “coffee” ) );[/cc_d]
And here’s the output:
[cc_text]#1
#2
#1 called with coffee, returning false
#2 called with coffee, returning true
Last sc2 callback returned true[/cc_text]