| <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="id2537324"></a>Design Rationale</h2></div></div></div> |
| <div class="toc"><dl> |
| <dt><span class="section"><a href="s06.html#id2537332">Choice of Slot Definitions</a></span></dt> |
| <dt><span class="section"><a href="s06.html#id2537416">User-level Connection Management</a></span></dt> |
| <dt><span class="section"><a href="s06.html#id2537581">Combiner Interface</a></span></dt> |
| <dt><span class="section"><a href="s06.html#id2537661">Connection Interfaces: += operator</a></span></dt> |
| <dt><span class="section"><a href="s06.html#id2537833"><code class="computeroutput">trackable</code> rationale</a></span></dt> |
| <dt><span class="section"><a href="s06.html#id2538016">Comparison with other Signal/Slot implementations</a></span></dt> |
| </dl></div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="id2537332"></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="id2537416"></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#id616339-bb">connect</a>(slot)</code> is |
| performed via |
| <code class="computeroutput">sig.<a class="link" href="../boost/signalN.html#id662943-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#id662943-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="id2537581"></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="id2537661"></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#id616339-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="id2537833"></a><code class="computeroutput">trackable</code> rationale</h3></div></div></div> |
| <div class="toc"><dl> |
| <dt><span class="section"><a href="s06.html#id2537874"><code class="computeroutput">trackable</code> copying behavior</a></span></dt> |
| <dt><span class="section"><a href="s06.html#id2537933">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="id2537874"></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="id2537933"></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="id2538016"></a>Comparison with other Signal/Slot implementations</h3></div></div></div> |
| <div class="toc"><dl> |
| <dt><span class="section"><a href="s06.html#id2538022">libsigc++</a></span></dt> |
| <dt><span class="section"><a href="s06.html#id2538078">.NET delegates</a></span></dt> |
| </dl></div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="id2538022"></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="id2538078"></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> |