Signals and Slots are an implementation of the Observer Pattern. Essentially, when a Signal is emitted, a list of connected Observers (called slots) are called.
There have been several D implementations of Signals and Slots. This version makes use of several new features in D, which make using it simpler and less error prone. In particular, it is no longer necessary to instrument the slots.
Mixin to create a signal within a class object.
Different signals can be added to a class by naming the mixins.
import std.signals; import std.stdio; class Observer { // our slot void watch(string msg, int i) { writefln("Observed msg '%s' and value %s", msg, i); } } class Foo { int value() { return _value; } int value(int v) { if (v != _value) { _value = v; // call all the connected slots with the two parameters emit("setting new value", v); } return v; } // Mix in all the code we need to make Foo into a signal mixin Signal!(string, int); private : int _value; } void main() { Foo a = new Foo; Observer o = new Observer; a.value = 3; // should not call o.watch() a.connect(&o.watch); // o.watch is the slot a.value = 4; // should call o.watch() a.disconnect(&o.watch); // o.watch is no longer a slot a.value = 5; // so should not call o.watch() a.connect(&o.watch); // connect again a.value = 6; // should call o.watch() destroy(o); // destroying o should automatically disconnect it a.value = 7; // should not call o.watch() }which should print:
Observed msg 'setting new value' and value 4 Observed msg 'setting new value' and value 6
A slot is implemented as a delegate. The slot_t is the type of the delegate. The delegate must be to an instance of a class or an interface to a class instance. Delegates to struct instances or nested functions must not be used as slots.
Call each of the connected slots, passing the argument(s) i to them.
Add a slot to the list of slots to be called when emit() is called.
Remove a slot from the list of slots to be called when emit() is called.