Main Page | Alphabetical List | Class List | File List | Class Members | File Members

dcouple Documentation

0.2

Generated documentation is inclomplete/incorrect

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.

Contents

  1. Introduction
  2. The Point of Management
  3. Connections
  4. Signals
  5. Slots
  6. Examples
  7. Project Status

Introduction

The "signal and slot" mechanism is a type-safe alternative to using call-back functions through function pointers. It can be used to equip objects and program components with an interface through which the components can be tied together into systems that were not envisioned at the time of design of the components. The mechanism has its widest application in GUI programming. For further information see the file Resources.txt.

The Point of Management

Obviously a signal can be implemented as a class or struct with a container for delegates. Connections can then be made by adding delegates (pointers to member functions) to the container, and when the signal is called to emit, it calls all the member functions registered with the signal. The member functions are behaving like slots, and there is no distinction between slots and member functions. The connection can be made from any place where both the signal and the slot are in scope. Breaking (disconnecting) an existing connection happens by removing the appropriate delegate from the container in the appropriate signal, so the same information is needed as at the time when the connection was established. An implementation of this design is provided by Andy Friesen in listener.d.

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.

Connections

Both Signals and Slots 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);
In the current implementation, a pre-existing identical connection is detected, and making the same connection more than once (as above) has no effect [1].

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:

connect(okButton.pressed, areYouSure.yes);
connect(areYouSure.yes, okButton.pressed);

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);
will result in a compile error along the lines of

test.d(87): function connect (Slot s) does not match argument types (Slot )

and

connect(counter.contentsChanged, areYouSure.yes);
will complain during program execution like

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.

Signals

A class can be equipped with a signal by giving it a templated member like so:
Signal!(int) contentsChanged;
Naturally, it must be newed in the constructor.
contentsChanged = new Signal!(int)(this);
Currently, a pointer to the object owning the signal is required passed in the constructor (this may change in the future). The owner must implement the SignalManager interface, which allows it to keep a list over its signals [2].

The signal can then be emitted by calling

contentsChanged.emit(myVal);

Slots

A class can be equipped with a slot by giving it a templated member like so:
Slot!(int) set;
It should be related to one of the member functions at the time of initialisation:
set = new Slot!(int)(this, &setVal);
where setVal is the member function that you want to be called when a signal arrives,
void setVal(int i) { ... }
Again, a pointer to the owning object is required passed in the constructor, and the owner must implement the SlotManager interface [2].

Currently, dcouple supports signals and slots with up to seven arguments. More can easily be added, although their practicality can be questioned.

Examples

More examples can be found in the examples directory.

Project Status

This framework is in early development. One of the aspects that have not been considered is thread-safety. Feedback is appreciated!

[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.


Generated on Fri Sep 17 05:50:08 2004 for dcouple by doxygen 1.3.8