Due to incomplete support for the D programming language in Doxygen, the documentation behind the links above is both incomplete and incorrect. This page contains manually generated documentation to make up for that.
The problem is, that when an object to which signals are connected is destructed, the connection must be broken in order to prevent an access violation. So slots need to be aware of existing connections just as well as signals are. The matter of disconnection and destruction is delicate in D, because the general rule is that no references to other objects may appear in destructors (see the specs) because finalisation is non-deterministic. In other words, the referred to objects may not exist any more, again resulting in an access violation.
Apart from gracefull destruction, there are other situations in which the receiving end may want to break a connection. One of them is that in D, objects that are not in use anymore will not be garbage collected if it still has connections to it, because they count as a reference. So you may want to give objects that contain signals and/or slots a method that shuts down all connections to and from it when you no longer need it.
In the following, we will cover different aspects of this implementation of managed signals and slots. We will start with making connections, because signals and slots are connected more often than they are defined.
Signal
s and Slot
s have a method called connect()
, and it does not matter which one you call. So if there is a signal in okButton
called pressed
and a slot in areYouSure
called yes
, the following are equivalent: okButton.pressed.connect(areYouSure.yes); areYouSure.yes.connect(okButton.pressed);
As they say at Trolltech: "syntax matters". We can mimmic the syntax for making a connection that Trolltech advocates. In fact our syntax is even less verbose than theirs, and thanks to the (limited) support for real-time type information (RTTI) in D, we can do without template functions. By not using a macro, our users need not bother about the order of arguments either. Again, the following are equivalent, to each other as well as to the above calls:
Signals and slots may have arguments, by which information can be transmitted between program components. When trying to establish a connection, the signal and slot must be compatible in the number and types of their arguments. When calling the connect() member function on incompatible signals and slots, compilation will not succeed. When calling the free connect() function this way, a run-time warning will be given, and no connection will be made. For example, if there is a counter
with a signal called contentsChanged
with an int
argument, and areYouSure.yes
has no arguments,
counter.contentsChanged.connect(areYouSure.yes);
test.d(87): function connect (Slot s) does not match argument types (Slot )
and
connect(counter.contentsChanged, areYouSure.yes);
dcouple WARNING: CounterWidget.Signal!(int) is incompatible with DialogWidget.Slot!(); not connected. (Sorry, no line number...)
The indication of argument mis-match works with build-in types as well as custom classes, at least in this run-time case. We would have liked to provide a file and line number and use object names in stead of class names, but currently this is the best we can do.
Connections can be removed by calling one of the disconnect() functions analogously. This is taken care of automatically when a signal or slot is deleted.
Signal!(int) contentsChanged;
contentsChanged = new Signal!(int)(this);
The signal can then be emitted by calling
contentsChanged.emit(myVal);
Slot!(int) set;
set = new Slot!(int)(this, &setVal);
setVal
is the member function that you want to be called when a signal arrives, void setVal(int i) { ... }
Currently, dcouple supports signals and slots with up to seven arguments. More can easily be added, although their practicality can be questioned.
[1] In this we deviate from the behaviour of Qt, in which a slot receives a signal as many times per emission as connections were made.
[2] At the time of this writing, references to interfaces are partly broken in D (see for example this post). Until a fix is in place, owning classes must derive from the class SignalSlotManager in stead, and override its member functions.