Signals and Slots in D

Walter Bright newshound at digitalmars.com
Thu Sep 28 19:33:51 PDT 2006


Walter Bright wrote:
> Some of the boilerplate can be eliminated with a mixin.

Here's the mixin. Actually, 3 of them, one each for 0 arguments, 1 
argument, and 2 arguments. I added a disconnect() function. Note how 
trivial it is to use - no need for preprocessing.

import std.stdio;

template Signal()	// for 0 arguments
{
     void emit()
     {
         foreach (dg; slots)
	    dg();
     }

     void connect( void delegate() dg)
     {
         slots ~= dg;
     }

     void disconnect( void delegate() dg)
     {
	for (size_t i = 0; i < slots.length; i++)
	{
	    if (slots[i] == dg)
	    {
		if (i + 1 == slots.length)
		    slots = slots[0 .. i];
		else
		    slots = slots[0 .. i] ~ slots[i + 1 .. length];
	    }
	}
     }

   private:
     void delegate()[] slots;
}

template Signal(T1)	// for one argument
{
     void emit( T1 i )
     {
         foreach (dg; slots)
	    dg(i);
     }

     void connect( void delegate(T1) dg)
     {
         slots ~= dg;
     }

     void disconnect( void delegate(T1) dg)
     {
	for (size_t i = 0; i < slots.length; i++)
	{
	    if (slots[i] == dg)
	    {
		if (i + 1 == slots.length)
		    slots = slots[0 .. i];
		else
		    slots = slots[0 .. i] ~ slots[i + 1 .. length];
	    }
	}
     }

   private:
     void delegate(T1)[] slots;
}

template Signal(T1, T2) // for two arguments
{
     void emit( T1 i, T2 j )
     {
         foreach (dg; slots)
	    dg(i, j);
     }

     void connect( void delegate(T1, T2) dg)
     {
         slots ~= dg;
     }

     void disconnect( void delegate(T1, T2) dg)
     {
	for (size_t i = 0; i < slots.length; i++)
	{
	    if (slots[i] == dg)
	    {
		if (i + 1 == slots.length)
		    slots = slots[0 .. i];
		else
		    slots = slots[0 .. i] ~ slots[i + 1 .. length];
	    }
	}
     }

   private:
     void delegate(T1, T2)[] slots;
}


class Foo
{
     this() { }

     int value() { return val; }

     void setValue( int v )
     {
       if ( v != val )
       {
	val = v;
	emit(v);
       }
     }

     mixin Signal!(int);	// adds in all the boilerplate to make it work

   private:
     int val;
}

void main()
{
     Foo a = new Foo;
     Foo b = new Foo;
     a.connect(&b.setValue);
     b.setValue( 11 );	 // a == 0  b == 11
     a.setValue( 79 );	 // a == 79 b == 79
     writefln(b.value()); // prints 79
     a.disconnect(&b.setValue);
     a.setValue( 80);
     writefln(b.value()); // prints 79
}



More information about the Digitalmars-d mailing list