Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

mainpage.docin

Go to the documentation of this file.
00001 /*! \mainpage
00002 
00003 <i>
00004 <b>NOTE:</b> Due to incomplete support for the D programming language in Doxygen, the documentation behind the links above is both incomplete and incorrect. If you want to be sure, consult the <A HREF="files.html">source code</A>. </i>This<i> page contains manually generated documentation to make up for that.
00005 </i>
00006 
00007 <H3>Contents</H3>
00008 <OL>
00009         <LI>\ref intro</LI>
00010         <LI>\ref management</LI>
00011         <LI>\ref connections</LI>
00012         <LI>\ref signals</LI>
00013         <OL>
00014                 <LI>\ref blockingsignals</LI>
00015                 <LI>\ref freesignals</LI>
00016         </OL>
00017         <LI>\ref slots</LI>
00018         <OL>
00019                 <LI>\ref private</LI>
00020                 <LI>\ref freeslots</LI>
00021         </OL>
00022         <LI>\ref bothplease</LI>
00023         <LI>\ref interfacesmixins</LI>
00024         <LI>\ref examples</LI>
00025         <LI>\ref status</LI>
00026         <LI>\ref changelog</LI>
00027 </OL>
00028 
00029 \section intro Introduction
00030 
00031 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 <A HREF="http://svn.dsource.org/svn/projects/dcouple/trunk/Resources.txt">Resources.txt</A>.
00032 
00033 \section management The Point of Management
00034 
00035 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 <A HREF="http://andy.tadan.us/d/listener.d">listener.d</A>.
00036 
00037 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 <A HREF="http://www.digitalmars.com/d/class.html">specs</A>) because finalisation is non-deterministic. In other words, the referred to objects may not exist any more, again resulting in an access violation. 
00038 
00039 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.
00040 
00041 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.
00042 
00043 
00044 \section connections Connections
00045 
00046 Both <tt>Signal</tt>s and <tt>Slot</tt>s have a method called <tt>connect()</tt>, and it does not matter which one you call. So if there is a signal in <tt>okButton</tt> called <tt>pressed</tt> and a slot in <tt>areYouSure</tt> called <tt>yes</tt>, the following are equivalent:
00047 \code
00048 okButton.pressed.connect(areYouSure.yes);
00049 areYouSure.yes.connect(okButton.pressed);
00050 \endcode
00051 Multiple identical connections may exist, which causes a slot to receive the same signal as many times per emission as connections were made. This is in accordance with <A HREF="http://doc.trolltech.com/4.0/signalsandslots.html">the behaviour of Qt</A>.
00052 
00053 As they <A HREF="http://doc.trolltech.com/4.0/templates.html">say</A> 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:
00054 \code
00055 import dcouple.connect;
00056 
00057 connect(okButton.pressed, areYouSure.yes);
00058 connect(areYouSure.yes, okButton.pressed);
00059 \endcode
00060 
00061 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 <tt>counter</tt> with a signal called <tt>contentsChanged</tt> with an <tt>int</tt> argument, and <tt>areYouSure.yes</tt> has no arguments,
00062 \code
00063 counter.contentsChanged.connect(areYouSure.yes);
00064 \endcode
00065 will result in a compile error along the lines of
00066 
00067 <tt>test.d(87): function connect (Slot s) does not match argument types (Slot )</tt>
00068 
00069 and
00070 \code
00071 connect(counter.contentsChanged, areYouSure.yes);
00072 \endcode
00073 will complain during program execution like
00074 
00075 <tt>dcouple WARNING: %CounterWidget.Signal!(int) is incompatible with %DialogWidget.Slot!(); not connected. (Sorry, no line number...)</tt>
00076 
00077 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.
00078 
00079 Connections can be removed by calling one of the disconnect() functions analogously. This is taken care of automatically when a signal or slot is destructed.
00080 
00081 
00082 \section signals Signals
00083 
00084 When a class is to be equipped with a signal, it is advised to make it inherit the SignalManager interface, and mix in its implementation.
00085 \code
00086 class Widget : SignalManager
00087 {
00088         mixin SignalManagement;
00089 \endcode
00090 This provides better run-time warnings when an incompatible connection is attempted to be made, and, more importantly, allows the object to be deleted in a controlled way, including its signals.
00091 
00092 The signal itself is defined by a templated member like so:
00093 \code
00094         Signal!(int) contentsChanged;
00095 \endcode
00096 Naturally, it must be newed in the constructor.
00097 \code
00098         this() {
00099                 contentsChanged = new Signal!(int)(this);
00100         }
00101 \endcode
00102 By passing the <tt>this</tt> pointer in the signal constructor, the signal marks itself as being owned by the manager (<tt>Widget</tt> in this case) and registers itself with it.
00103 
00104 The signal can then be emitted by calling
00105 \code
00106                 /*...*/
00107                 contentsChanged.emit(myVal);
00108                 /*...*/
00109 }
00110 \endcode
00111 
00112 
00113 \subsection blockingsignals Blocking Signals
00114 
00115 An object that is a SignalManager can temporarily be made to turn off its ordinary signals by means of the signalsBlocked(bool) property.
00116 \code
00117 Widget w = new Widget;
00118 /* Set connections etc. */
00119 w.signalsBlocked = true;
00120 contentsChanged.emit(myVal);    // The signal is not emitted.
00121 \endcode
00122 
00123 For the rare occasion that a signal must ignore the block of its owner, it can be defined as a NonBlockingSignal. Such a signal can be used to emit a <tt>destroyed</tt> signal in the destructor, for example.
00124 \code
00125 class Widget : SignalManager
00126 {
00127         mixin SignalManagement;
00128         NonBlockingSignal!() destroyed;
00129         this()
00130         {
00131                 destroyed = new NonBlockingSignal!(this);
00132         }
00133         ~this()
00134         {
00135                 destroyed.emit();
00136                 deleteSignals();        // See below.
00137         }
00138 }
00139 \endcode
00140 
00141 \note When you provide a destructor in a managing class, you are replacing the one that SignalManagement provides. You must therefore duplicate the contents from that destructor (with \c deleteSignals(); something like <tt>SM.~this()</tt>, where \c SM identifies the mixin, does not seem to work yet.).
00142 
00143 \warning One should be careful to rely on signals in a destructor to be emitted. Garbage collected objects have no deterministic finalisation, and therefore the signal (\c destroyed in this case) may have been deleted before the owner gets deleted (\c Widget in this case). It will work as intended if you delete the owner explicitly however.
00144 
00145 
00146 \subsection freesignals Free Signals
00147 
00148 A signal does not need to be owned, for example if it lives outside a class.
00149 \code
00150 Signal!() freeSignal = new Signal!()(null);
00151 \endcode
00152 
00153 A free signal can not be blocked through its owner of course. Blocking signals individually is not supported yet.
00154 
00155 
00156 
00157 \section slots Slots
00158 
00159 Slots are managed as well.
00160 \code
00161 class Widget : SlotManager
00162 {
00163         mixin SlotManagement;
00164 \endcode
00165 \anchor careful_free_slots The importance of a managing owner is more apparent for slots than for signals. If a slot outlives its owner (due to the non-deterministic finalisation of garbage collected objects) they still receive signals and it has been shown that the member functions with which they are associated <i>may still be operational</i> despite the object having been destructed. SlotManagement takes care that connections are broken and that all relevant actors leave the scene at the right moment.
00166 
00167 A slot is defined in the same way as signals are:
00168 \code
00169         Slot!(int) set;
00170 \endcode
00171 The slot should be related to one of the member functions at the time of initialisation:
00172 \code
00173         this()
00174         {
00175                 set = new Slot!(int)(this, &setVal);
00176         }
00177 \endcode
00178 where \c setVal is the member function that you want to be called when a signal arrives,
00179 \code
00180         void setVal(int i) { my_int = i; }
00181 private:
00182         int my_int;
00183 }
00184 \endcode
00185 
00186 The function reference on which a slot is created may be to any of the following
00187 <UL>
00188         <LI>a member function</LI>
00189         <LI>a static nested function</LI>
00190         <LI>a free function.</LI>
00191 </UL>
00192 \warning It is important that the slot object does not outlive the function that it references. Although you will be able to construct a slot that references a non-static nested function, it is not safe to do so. A segmentation fault will be the result if a slot attempts to call a function that has been garbage collected. For the same reason, when constructing a slot on a member function, that slot must be owned by the object (implementing a SlotManager) that has the member function. The destructor of the owner will remove the slot before the member function becomes garbage.
00193 
00194 When the nested function goes out of scope, it may be collected as garbage before the slot is destructed, which will result in a segmentation fault if the slot receives a signal at this moment.
00195 
00196 \subsection private Removing Duplicate Functionality in the API
00197 
00198 In the above example, the class interface has two methods for accomplishing the same thing. Calling <tt>setVal(5)</tt> is equivalent to calling <tt>set(5)</tt>. To simplify the API, \c setVal() may be made private.
00199 
00200 \subsection freeslots Free Slots (Experimental)
00201 
00202 Analogous to free signals, a slot can live outside a class.
00203 \code
00204 void message()
00205 {
00206         printf("You can turn a free function into a slot as well.\n");
00207 }
00208 
00209 void main()
00210 {
00211         Slot!() freeSlot = new Slot!()(null,&message);
00212         Signal!() freeSig = new Signal!()(null);
00213         connect(freeSig, freeSlot);
00214         freeSig.emit();
00215 }
00216 \endcode
00217 As mentioned \ref careful_free_slots "above", there is reason to be carefull with free slots, because their destruction is not linked with the life span of the function that they reference. It is best to disconnect free slots before their referenced function goes out of scope.
00218 
00219 There is one scenario in which a segmentation fault will happen even when only static functions are referenced. Suppose a special signal has been implemented (inheriting from some Signal template) that is guaranteed to emit when its owner (or itself) is being destructed. When such a signal remains alive until the program terminates, it will emit during the final garbage collection. Connected slots that are still alive will receive the signal, and call their referenced functions. But, even static functions are being collected at this point, and may have been collected before the signals and slots. As a result, the program may terminate with a segmentation fault.
00220 
00221 In the future, free slots may automatically register with a global static SlotManager. Before termination of the program, this manager may be called to disconnect all "free" slots, and thus prevent the segmentation fault.
00222 
00223 
00224 \section bothplease Both Signals and Slots
00225 
00226 Classes that own both signals and slots should inherit from \c SignalSlotManager and mix in the \c SignalSlotManagement implementation.
00227 
00228 Currently, dcouple supports signals and slots with up to seven arguments. More can easily be added, although their practicality can be questioned.
00229 
00230 
00231 \section interfacesmixins Extending Legacy Classes
00232 
00233 \note Currently there is a <A HREF="http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D.bugs/1846">bug</A> in dmd involving interfaces. The following will be possible in the future.
00234 
00235 Courtecy the concepts of interfaces and mixins of the D programming language, this implementation has the interesting property that existing (probably third-party) classes can be equipped with signals and slots without interfering with their inheritance tree. Given the following legacy class
00236 \code
00237 class ImportantClass : DeepInheritanceHierarchy
00238 {
00239         /*...*/
00240         P importantProperty() { return _prop; }
00241         void importantProperty(P prop) { _prop = prop; }
00242 private:
00243         P _prop;
00244 }
00245 \endcode
00246 A class like this can be extended in a straight forward manner, for example
00247 \code
00248 class ExtendedClass : ImportantClass, SignalSlotManager
00249 {
00250         mixin SignalSlotManagement;
00251         Signal!() propertyChanged;
00252         Slot!(P) updateProperty;
00253         this()
00254         {
00255                 propertyChanged = new Signal!()(this);
00256                 updateProperty = new Slot!(P)(this,&importantProperty);
00257         }
00258         void importantProperty(P prop)
00259         {
00260                 super.importantProperty(prop);
00261                 propertyChanged.emit();
00262         }
00263 }
00264 \endcode
00265 
00266 Without (working) interfaces, SignalSlotManager must be a class, and therefore positioned at the root of the inheritance tree.
00267 
00268 
00269 \section examples Examples
00270 
00271 More examples can be found in the <A HREF="../examples/">examples</A> directory.
00272 
00273 
00274 \section status Project Status
00275 
00276 This framework is in early development. One of the aspects that have not been considered is thread-safety. Feedback is appreciated! Any volunteers to benchmark against <A HREF="../../Resources.txt">other implementations</A>?
00277 
00278 
00279 \section changelog Changelog
00280 
00281 <UL>
00282   <LI> <b>version 0.3</b>
00283     <UL>
00284       <LI> Made to compile under dmd 0.131.
00285       <LI> Regenerated documentation with Doxygen 1.4.3.
00286       <LI> The management now works by means of an interface and mixin, so legacy classes can be equipped with signals and slots. Early dmd did not allow this due to a compiler bug.
00287       <LI> Multiple identical connections can exist. A slot receives a signal as many times per emit as connections were made.
00288       <LI> Slots receive a signal in the order in which they were connected.
00289     </UL>
00290 </UL>
00291 
00292 */

Generated on Mon Sep 12 22:10:39 2005 for dcouple by  doxygen 1.4.3