<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> <title>Design Rationale</title> <link rel="stylesheet" href="../../../doc/src/boostbook.css" type="text/css"> <meta name="generator" content="DocBook XSL Stylesheets V1.75.2"> <link rel="home" href="../index.html" title="The Boost C++ Libraries BoostBook Documentation Subset"> <link rel="up" href="../signals.html" title="Chapter 18. Boost.Signals"> <link rel="prev" href="s05.html" title="Design Overview"> <link rel="next" href="tests.html" title="Testsuite"> </head> <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> <table cellpadding="2" width="100%"><tr> <td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../boost.png"></td> <td align="center"><a href="../../../index.html">Home</a></td> <td align="center"><a href="../../../libs/libraries.htm">Libraries</a></td> <td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> <td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> <td align="center"><a href="../../../more/index.htm">More</a></td> </tr></table> <hr> <div class="spirit-nav"> <a accesskey="p" href="s05.html"><img src="../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../signals.html"><img src="../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="tests.html"><img src="../../../doc/src/images/next.png" alt="Next"></a> </div> <div class="section"> <div class="titlepage"><div><div><h2 class="title" style="clear: both"> <a name="id2547393"></a>Design Rationale</h2></div></div></div> <div class="toc"><dl> <dt><span class="section"><a href="s06.html#id2547401">Choice of Slot Definitions</a></span></dt> <dt><span class="section"><a href="s06.html#id2547478">User-level Connection Management</a></span></dt> <dt><span class="section"><a href="s06.html#id2547643">Combiner Interface</a></span></dt> <dt><span class="section"><a href="s06.html#id2547723">Connection Interfaces: += operator</a></span></dt> <dt><span class="section"><a href="s06.html#id2547894"><code class="computeroutput">trackable</code> rationale</a></span></dt> <dt><span class="section"><a href="s06.html#id2548077">Comparison with other Signal/Slot implementations</a></span></dt> </dl></div> <div class="section"> <div class="titlepage"><div><div><h3 class="title"> <a name="id2547401"></a>Choice of Slot Definitions</h3></div></div></div> <p> The definition of a slot differs amongst signals and slots libraries. Within Boost.Signals, a slot is defined in a very loose manner: it can be any function object that is callable given parameters of the types specified by the signal, and whose return value is convertible to the result type expected by the signal. However, alternative definitions have associated pros and cons that were considered prior to the construction of Boost.Signals.</p> <div class="itemizedlist"><ul class="itemizedlist" type="disc"> <li class="listitem"> <p><span class="bold"><strong>Slots derive from a specific base class</strong></span>: generally a scheme such as this will require all user-defined slots to derive from some library-specified <code class="computeroutput">Slot</code> abstract class that defines a virtual function calling the slot. Adaptors can be used to convert a definition such as this to a definition similar to that used by Boost.Signals, but the use of a large number of small adaptor classes containing virtual functions has been found to cause an unacceptable increase in the size of executables (polymorphic class types require more code than non-polymorphic types).</p> <p> This approach does have the benefit of simplicity of implementation and user interface, from an object-oriented perspective.</p> </li> <li class="listitem"><p><span class="bold"><strong>Slots constructed from a set of primitives</strong></span>: in this scheme the slot can have a limited set of types (often derived from a common abstract base class) that are constructed from some library-defined set of primitives that often include conversions from free function pointers and member function pointers, and a limited set of binding capabilities. Such an approach is reasonably simple and cover most common cases, but it does not allow a large degree of flexibility in slot construction. Libraries for function object composition have become quite advanced and it is out of the scope of a signals and slots library to encorporate such enhancements. Thus Boost.Signals does not include argument binding or function object composition primitives, but instead provides a hook (via the <code class="computeroutput"><a class="link" href="../boost/visit_each.html" title="Function template visit_each">visit_each</a></code> mechanism) that allows existing binder/composition libraries to provide the necessary information to Signals.</p></li> </ul></div> <p> Users not satisfied with the slot definition choice may opt to replace the default slot function type with an alternative that meets their specific needs.</p> </div> <div class="section"> <div class="titlepage"><div><div><h3 class="title"> <a name="id2547478"></a>User-level Connection Management</h3></div></div></div> <p> Users need to have fine control over the connection of signals to slots and their eventual disconnection. The approach taken by Boost.Signals is to return a <code class="computeroutput"><a class="link" href="../boost/signals/connection.html" title="Class connection">connection</a></code> object that enables connected/disconnected query, manual disconnection, and an automatic disconnection on destruction mode. Some other possible interfaces include:</p> <div class="itemizedlist"><ul class="itemizedlist" type="disc"> <li class="listitem"><p><span class="bold"><strong>Pass slot to disconnect</strong></span>: in this interface model, the disconnection of a slot connected with <code class="computeroutput">sig.<a class="link" href="../boost/signalN.html#id640401-bb">connect</a>(slot)</code> is performed via <code class="computeroutput">sig.<a class="link" href="../boost/signalN.html#id646059-bb">disconnect</a>(slot)</code>. Internally, a linear search using slot comparison is performed and the slot, if found, is removed from the list. Unfortunately, querying connectedness will generally also end up as linear-time operations. This model also fails for implementation reasons when slots become more complex than simple function pointers, member function pointers and a limited set of compositions and argument binders: to match the slot given in the call to <code class="computeroutput"><a class="link" href="../boost/signalN.html#id646059-bb">disconnect</a></code> with an existing slot we would need to be able to compare arbitrary function objects, which is not feasible.</p></li> <li class="listitem"> <p><span class="bold"><strong>Pass a token to disconnect</strong></span>: this approach identifies slots with a token that is easily comparable (e.g., a string), enabling slots to be arbitrary function objects. While this approach is essentially equivalent to the approach taken by Boost.Signals, it is possibly more error-prone for several reasons:</p> <div class="itemizedlist"><ul class="itemizedlist" type="circle"> <li class="listitem"><p>Connections and disconnections must be paired, so the problem becomes similar to the problems incurred when pairing <code class="computeroutput">new</code> and <code class="computeroutput">delete</code> for dynamic memory allocation. While errors of this sort would not be catastrophic for a signals and slots implementation, their detection is generally nontrivial.</p></li> <li class="listitem"><p>Tokens must be unique, otherwise two slots will have the same name and will be indistinguishable. In environments where many connections will be made dynamically, name generation becomes an additional task for the user. Uniqueness of tokens also results in an additional failure mode when attempting to connect a slot using a token that has already been used.</p></li> <li class="listitem"><p>More parameterization would be required, because the token type must be user-defined. Additional parameterization steepens the learning curver and overcomplicates a simple interface.</p></li> </ul></div> <p> This type of interface is supported in Boost.Signals via the slot grouping mechanism. It augments the <code class="computeroutput"><a class="link" href="../boost/signals/connection.html" title="Class connection">connection</a></code> object-based connection management scheme.</p> </li> </ul></div> </div> <div class="section"> <div class="titlepage"><div><div><h3 class="title"> <a name="id2547643"></a>Combiner Interface</h3></div></div></div> <p> The Combiner interface was chosen to mimic a call to an algorithm in the C++ standard library. It is felt that by viewing slot call results as merely a sequence of values accessed by input iterators, the combiner interface would be most natural to a proficient C++ programmer. Competing interface design generally required the combiners to be constructed to conform to an interface that would be customized for (and limited to) the Signals library. While these interfaces are generally enable more straighforward implementation of the signals & slots libraries, the combiners are unfortunately not reusable (either in other signals & slots libraries or within other generic algorithms), and the learning curve is steepened slightly to learn the specific combiner interface.</p> <p> The Signals formulation of combiners is based on the combiner using the "pull" mode of communication, instead of the more complex "push" mechanism. With a "pull" mechanism, the combiner's state can be kept on the stack and in the program counter, because whenever new data is required (i.e., calling the next slot to retrieve its return value), there is a simple interface to retrieve that data immediately and without returning from the combiner's code. Contrast this with the "push" mechanism, where the combiner must keep all state in class members because the combiner's routines will be invoked for each signal called. Compare, for example, a combiner that returns the maximum element from calling the slots. If the maximum element ever exceeds 100, no more slots are to be called.</p> <div class="informaltable"><table class="table"> <colgroup> <col> <col> </colgroup> <thead><tr> <th align="left"><p>Pull</p></th> <th align="left"><p>Push</p></th> </tr></thead> <tbody><tr> <td align="left"> <pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> struct pull_max { typedef int result_type; template<typename InputIterator> result_type operator()(InputIterator first, InputIterator last) { if (first == last) throw std::runtime_error("Empty!"); int max_value = *first++; while(first != last && *first <= 100) { if (*first > max_value) max_value = *first; ++first; } return max_value; } }; </pre> </td> <td align="left"> <pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> struct push_max { typedef int result_type; push_max() : max_value(), got_first(false) {} // returns false when we want to stop bool operator()(int result) { if (result > 100) return false; if (!got_first) { got_first = true; max_value = result; return true; } if (result > max_value) max_value = result; return true; } int get_value() const { if (!got_first) throw std::runtime_error("Empty!"); return max_value; } private: int max_value; bool got_first; }; </pre> </td> </tr></tbody> </table></div> <p>There are several points to note in these examples. The "pull" version is a reusable function object that is based on an input iterator sequence with an integer <code class="computeroutput">value_type</code>, and is very straightforward in design. The "push" model, on the other hand, relies on an interface specific to the caller and is not generally reusable. It also requires extra state values to determine, for instance, if any elements have been received. Though code quality and ease-of-use is generally subjective, the "pull" model is clearly shorter and more reusable and will often be construed as easier to write and understand, even outside the context of a signals & slots library.</p> <p> The cost of the "pull" combiner interface is paid in the implementation of the Signals library itself. To correctly handle slot disconnections during calls (e.g., when the dereference operator is invoked), one must construct the iterator to skip over disconnected slots. Additionally, the iterator must carry with it the set of arguments to pass to each slot (although a reference to a structure containing those arguments suffices), and must cache the result of calling the slot so that multiple dereferences don't result in multiple calls. This apparently requires a large degree of overhead, though if one considers the entire process of invoking slots one sees that the overhead is nearly equivalent to that in the "push" model, but we have inverted the control structures to make iteration and dereference complex (instead of making combiner state-finding complex).</p> </div> <div class="section"> <div class="titlepage"><div><div><h3 class="title"> <a name="id2547723"></a>Connection Interfaces: += operator</h3></div></div></div> <p> Boost.Signals supports a connection syntax with the form <code class="computeroutput">sig.<a class="link" href="../boost/signalN.html#id640401-bb">connect</a>(slot)</code>, but a more terse syntax <code class="computeroutput">sig += slot</code> has been suggested (and has been used by other signals & slots implementations). There are several reasons as to why this syntax has been rejected:</p> <div class="itemizedlist"><ul class="itemizedlist" type="disc"> <li class="listitem"><p><span class="bold"><strong>It's unnecessary</strong></span>: the connection syntax supplied by Boost.Signals is no less powerful that that supplied by the <code class="computeroutput">+=</code> operator. The savings in typing (<code class="computeroutput">connect()</code> vs. <code class="computeroutput">+=</code>) is essentially negligible. Furthermore, one could argue that calling <code class="computeroutput">connect()</code> is more readable than an overload of <code class="computeroutput">+=</code>.</p></li> <li class="listitem"><p><span class="bold"><strong>Ambiguous return type</strong></span>: there is an ambiguity concerning the return value of the <code class="computeroutput">+=</code> operation: should it be a reference to the signal itself, to enable <code class="computeroutput">sig += slot1 += slot2</code>, or should it return a <code class="computeroutput"><a class="link" href="../boost/signals/connection.html" title="Class connection">connection</a></code> for the newly-created signal/slot connection?</p></li> <li class="listitem"> <p><span class="bold"><strong>Gateway to operators -=, +</strong></span>: when one has added a connection operator <code class="computeroutput">+=</code>, it seems natural to have a disconnection operator <code class="computeroutput">-=</code>. However, this presents problems when the library allows arbitrary function objects to implicitly become slots, because slots are no longer comparable. </p> <p> The second obvious addition when one has <code class="computeroutput">operator+=</code> would be to add a <code class="computeroutput">+</code> operator that supports addition of multiple slots, followed by assignment to a signal. However, this would require implementing <code class="computeroutput">+</code> such that it can accept any two function objects, which is technically infeasible.</p> </li> </ul></div> </div> <div class="section"> <div class="titlepage"><div><div><h3 class="title"> <a name="id2547894"></a><code class="computeroutput">trackable</code> rationale</h3></div></div></div> <div class="toc"><dl> <dt><span class="section"><a href="s06.html#id2547936"><code class="computeroutput">trackable</code> copying behavior</a></span></dt> <dt><span class="section"><a href="s06.html#id2547994">Why derivation from <code class="computeroutput">trackable</code>?</a></span></dt> </dl></div> <p> The <code class="computeroutput"><a class="link" href="../boost/signals/trackable.html" title="Class trackable">trackable</a></code> class is the primary user interface to automatic connection lifetime management, and its design affects users directly. Two issues stick out most: the odd copying behavior of <code class="computeroutput">trackable</code>, and the limitation requiring users to derive from <code class="computeroutput">trackable</code> to create types that can participate in automatic connection management.</p> <div class="section"> <div class="titlepage"><div><div><h4 class="title"> <a name="id2547936"></a><code class="computeroutput">trackable</code> copying behavior</h4></div></div></div> <p> The copying behavior of <code class="computeroutput"><a class="link" href="../boost/signals/trackable.html" title="Class trackable">trackable</a></code> is essentially that <code class="computeroutput"><a class="link" href="../boost/signals/trackable.html" title="Class trackable">trackable</a></code> subobjects are never copied; instead, the copy operation is merely a no-op. To understand this, we look at the nature of a signal-slot connection and note that the connection is based on the entities that are being connected; when one of the entities is destroyed, the connection is destroyed. Therefore, when a <code class="computeroutput"><a class="link" href="../boost/signals/trackable.html" title="Class trackable">trackable</a></code> subobject is copied, we cannot copy the connections because the connections don't refer to the target entity - they refer to the source entity. This reason is dual to the reason signals are noncopyable: the slots connected to them are connected to that particular signal, not the data contained in the signal.</p> </div> <div class="section"> <div class="titlepage"><div><div><h4 class="title"> <a name="id2547994"></a>Why derivation from <code class="computeroutput">trackable</code>?</h4></div></div></div> <p> For <code class="computeroutput"><a class="link" href="../boost/signals/trackable.html" title="Class trackable">trackable</a></code> to work properly, there are two constraints:</p> <div class="itemizedlist"><ul class="itemizedlist" type="disc"> <li class="listitem"><p><code class="computeroutput"><a class="link" href="../boost/signals/trackable.html" title="Class trackable">trackable</a></code> must have storage space to keep track of all connections made to this object.</p></li> <li class="listitem"><p><code class="computeroutput"><a class="link" href="../boost/signals/trackable.html" title="Class trackable">trackable</a></code> must be notified when the object is being destructed so that it can disconnect its connections.</p></li> </ul></div> <p>Clearly, deriving from <code class="computeroutput"><a class="link" href="../boost/signals/trackable.html" title="Class trackable">trackable</a></code> meets these two guidelines. We have not yet found a superior solution.</p> </div> </div> <div class="section"> <div class="titlepage"><div><div><h3 class="title"> <a name="id2548077"></a>Comparison with other Signal/Slot implementations</h3></div></div></div> <div class="toc"><dl> <dt><span class="section"><a href="s06.html#id2548084">libsigc++</a></span></dt> <dt><span class="section"><a href="s06.html#id2548140">.NET delegates</a></span></dt> </dl></div> <div class="section"> <div class="titlepage"><div><div><h4 class="title"> <a name="id2548084"></a>libsigc++</h4></div></div></div> <p> <a href="http://libsigc.sourceforge.net" target="_top">libsigc++</a> is a C++ signals & slots library that originally started as part of an initiative to wrap the C interfaces to <a href="http://www.gtk.org" target="_top">GTK</a> libraries in C++, and has grown to be a separate library maintained by Karl Nelson. There are many similarities between libsigc++ and Boost.Signals, and indeed Boost.Signals was strongly influenced by Karl Nelson and libsigc++. A cursory inspection of each library will find a similar syntax for the construction of signals and in the use of connections and automatic connection lifetime management. There are some major differences in design that separate these libraries:</p> <div class="itemizedlist"><ul class="itemizedlist" type="disc"> <li class="listitem"><p><span class="bold"><strong>Slot definitions</strong></span>: slots in libsigc++ are created using a set of primitives defined by the library. These primitives allow binding of objects (as part of the library), explicit adaptation from the argument and return types of the signal to the argument and return types of the slot (libsigc++ is, by default, more strict about types than Boost.Signals). A discussion of this approach with a comparison against the approach taken by Boost.Signals is given in Choice of Slot Definitions.</p></li> <li class="listitem"><p><span class="bold"><strong>Combiner/Marshaller interface</strong></span>: the equivalent to Boost.Signals combiners in libsigc++ are the marshallers. Marshallers are similar to the "push" interface described in Combiner Interface, and a proper treatment of the topic is given there.</p></li> </ul></div> </div> <div class="section"> <div class="titlepage"><div><div><h4 class="title"> <a name="id2548140"></a>.NET delegates</h4></div></div></div> <p> <a href="http://www.microsoft.com" target="_top">Microsoft</a> has introduced the .NET Framework and an associated set of languages and language extensions, one of which is the delegate. Delegates are similar to signals and slots, but they are more limited than most C++ signals and slots implementations in that they:</p> <div class="itemizedlist"><ul class="itemizedlist" type="disc"> <li class="listitem"><p>Require exact type matches between a delegate and what it is calling.</p></li> <li class="listitem"><p>Only return the result of the last target called, with no option for customization.</p></li> <li class="listitem"><p>Must call a method with <code class="computeroutput">this</code> already bound.</p></li> </ul></div> </div> </div> </div> <table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> <td align="left"><p><small>Last revised: November 25, 2007 at 18:38:02 +0000</small></p></td> <td align="right"><div class="copyright-footer">Copyright © 2001-2004 Douglas Gregor<p>Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file <code class="filename">LICENSE_1_0.txt</code> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)</p> </div></td> </tr></table> <hr> <div class="spirit-nav"> <a accesskey="p" href="s05.html"><img src="../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../signals.html"><img src="../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="tests.html"><img src="../../../doc/src/images/next.png" alt="Next"></a> </div> </body> </html>