Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/doc/html/signals/s06.html @ 25

Last change on this file since 25 was 12, checked in by landauf, 17 years ago

added boost

File size: 23.2 KB
Line 
1<html>
2<head>
3<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
4<title>Design Rationale</title>
5<link rel="stylesheet" href="../boostbook.css" type="text/css">
6<meta name="generator" content="DocBook XSL Stylesheets V1.69.1">
7<link rel="start" href="../index.html" title="The Boost C++ Libraries">
8<link rel="up" href="../signals.html" title="Chapter 9. Boost.Signals">
9<link rel="prev" href="s05.html" title="Design Overview">
10<link rel="next" href="tests.html" title="Testsuite">
11</head>
12<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
13<table cellpadding="2" width="100%">
14<td valign="top"><img alt="boost.png (6897 bytes)" width="277" height="86" src="../../../boost.png"></td>
15<td align="center"><a href="../../../index.htm">Home</a></td>
16<td align="center"><a href="../../../libs/libraries.htm">Libraries</a></td>
17<td align="center"><a href="../../../people/people.htm">People</a></td>
18<td align="center"><a href="../../../more/faq.htm">FAQ</a></td>
19<td align="center"><a href="../../../more/index.htm">More</a></td>
20</table>
21<hr>
22<div class="spirit-nav">
23<a accesskey="p" href="s05.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../signals.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="tests.html"><img src="../images/next.png" alt="Next"></a>
24</div>
25<div class="section" lang="en">
26<div class="titlepage"><div><div><h3 class="title">
27<a name="id2739447"></a>Design Rationale</h3></div></div></div>
28<div class="toc"><dl>
29<dt><span class="section"><a href="s06.html#id2739454">Choice of Slot Definitions</a></span></dt>
30<dt><span class="section"><a href="s06.html#id2739537">User-level Connection Management</a></span></dt>
31<dt><span class="section"><a href="s06.html#id2739686">Combiner Interface</a></span></dt>
32<dt><span class="section"><a href="s06.html#id2739833">Connection Interfaces: +=  operator</a></span></dt>
33<dt><span class="section"><a href="s06.html#id2739993"><code class="computeroutput">trackable</code> rationale</a></span></dt>
34<dt><span class="section"><a href="s06.html#id2740156">Comparison with other Signal/Slot implementations</a></span></dt>
35</dl></div>
36<div class="section" lang="en">
37<div class="titlepage"><div><div><h4 class="title">
38<a name="id2739454"></a>Choice of Slot Definitions</h4></div></div></div>
39<p> The definition of a slot differs amongst signals and slots
40    libraries. Within Boost.Signals, a slot is defined in a very loose
41    manner: it can be any function object that is callable given
42    parameters of the types specified by the signal, and whose return
43    value is convertible to the result type expected by the
44    signal. However, alternative definitions have associated pros and
45    cons that were considered prior to the construction of
46    Boost.Signals.</p>
47<div class="itemizedlist"><ul type="disc">
48<li>
49<p><span class="bold"><strong>Slots derive from a specific base
50        class</strong></span>: generally a scheme such as this will require
51        all user-defined slots to derive from some library-specified
52        <code class="computeroutput">Slot</code> abstract class that defines a virtual
53        function calling the slot. Adaptors can be used to convert a
54        definition such as this to a definition similar to that used
55        by Boost.Signals, but the use of a large number of small
56        adaptor classes containing virtual functions has been found to
57        cause an unacceptable increase in the size of executables
58        (polymorphic class types require more code than
59        non-polymorphic types).</p>
60<p> This approach does have the benefit of simplicity of
61        implementation and user interface, from an object-oriented
62        perspective.</p>
63</li>
64<li><p><span class="bold"><strong>Slots constructed from a set of
65        primitives</strong></span>: in this scheme the slot can have a
66        limited set of types (often derived from a common abstract
67        base class) that are constructed from some library-defined set
68        of primitives that often include conversions from free
69        function pointers and member function pointers, and a limited
70        set of binding capabilities. Such an approach is reasonably
71        simple and cover most common cases, but it does not allow a
72        large degree of flexibility in slot construction. Libraries
73        for function object composition have become quite advanced and
74        it is out of the scope of a signals and slots library to
75        encorporate such enhancements. Thus Boost.Signals does not
76        include argument binding or function object composition
77        primitives, but instead provides a hook (via the
78        <code class="computeroutput"><a href="../visit_each.html" title="Function template visit_each">visit_each</a></code>
79        mechanism) that allows existing binder/composition libraries
80        to provide the necessary information to Signals.</p></li>
81</ul></div>
82<p> Users not satisfied with the slot definition choice may opt
83    to replace the default slot function type with an alternative that
84    meets their specific needs.</p>
85</div>
86<div class="section" lang="en">
87<div class="titlepage"><div><div><h4 class="title">
88<a name="id2739537"></a>User-level Connection Management</h4></div></div></div>
89<p> Users need to have fine control over the connection of
90    signals to slots and their eventual disconnection. The approach
91    taken by Boost.Signals is to return a
92    <code class="computeroutput"><a href="../connection.html" title="Class connection">connection</a></code> object that enables
93    connected/disconnected query, manual disconnection, and an
94    automatic disconnection on destruction mode. Some other possible
95    interfaces include:</p>
96<div class="itemizedlist"><ul type="disc">
97<li><p><span class="bold"><strong>Pass slot to
98        disconnect</strong></span>: in this interface model, the
99        disconnection of a slot connected with
100        <code class="computeroutput">sig.<a href="../signalN.html#id2551390-bb">connect</a>(slot)</code> is
101        performed via
102        <code class="computeroutput">sig.<a href="../signalN.html#id2582644-bb">disconnect</a>(slot)</code>. Internally,
103        a linear search using slot comparison is performed and the
104        slot, if found, is removed from the list. Unfortunately,
105        querying connectedness will generally also end up as
106        linear-time operations. This model also fails for
107        implementation reasons when slots become more complex than
108        simple function pointers, member function pointers and a
109        limited set of compositions and argument binders: to match the
110        slot given in the call to
111        <code class="computeroutput"><a href="../signalN.html#id2582644-bb">disconnect</a></code> with an
112        existing slot we would need to be able to compare arbitrary
113        function objects, which is not feasible.</p></li>
114<li>
115<p><span class="bold"><strong>Pass a token to
116        disconnect</strong></span>: this approach identifies slots with a
117        token that is easily comparable (e.g., a string), enabling
118        slots to be arbitrary function objects. While this approach is
119        essentially equivalent to the approach taken by Boost.Signals,
120        it is possibly more error-prone for several reasons:</p>
121<div class="itemizedlist"><ul type="circle">
122<li><p>Connections and disconnections must be paired, so
123            the problem becomes similar to the problems incurred when
124            pairing <code class="computeroutput">new</code> and <code class="computeroutput">delete</code> for
125            dynamic memory allocation. While errors of this sort would
126            not be catastrophic for a signals and slots
127            implementation, their detection is generally
128            nontrivial.</p></li>
129<li><p>Tokens must be unique, otherwise two slots will have
130            the same name and will be indistinguishable. In
131            environments where many connections will be made
132            dynamically, name generation becomes an additional task
133            for the user. Uniqueness of tokens also results in an
134            additional failure mode when attempting to connect a slot
135            using a token that has already been used.</p></li>
136<li><p>More parameterization would be required, because the
137            token type must be user-defined. Additional
138            parameterization steepens the learning curver and
139            overcomplicates a simple interface.</p></li>
140</ul></div>
141<p> This type of interface is supported in Boost.Signals
142        via the slot grouping mechanism. It augments the
143        <code class="computeroutput"><a href="../connection.html" title="Class connection">connection</a></code> object-based
144        connection management scheme.</p>
145</li>
146</ul></div>
147</div>
148<div class="section" lang="en">
149<div class="titlepage"><div><div><h4 class="title">
150<a name="id2739686"></a>Combiner Interface</h4></div></div></div>
151<p> The Combiner interface was chosen to mimic a call to an
152    algorithm in the C++ standard library. It is felt that by viewing
153    slot call results as merely a sequence of values accessed by input
154    iterators, the combiner interface would be most natural to a
155    proficient C++ programmer. Competing interface design generally
156    required the combiners to be constructed to conform to an
157    interface that would be customized for (and limited to) the
158    Signals library. While these interfaces are generally enable more
159    straighforward implementation of the signals &amp; slots
160    libraries, the combiners are unfortunately not reusable (either in
161    other signals &amp; slots libraries or within other generic
162    algorithms), and the learning curve is steepened slightly to learn
163    the specific combiner interface.</p>
164<p> The Signals formulation of combiners is based on the
165    combiner using the "pull" mode of communication, instead of the
166    more complex "push" mechanism. With a "pull" mechanism, the
167    combiner's state can be kept on the stack and in the program
168    counter, because whenever new data is required (i.e., calling the
169    next slot to retrieve its return value), there is a simple
170    interface to retrieve that data immediately and without returning
171    from the combiner's code. Contrast this with the "push" mechanism,
172    where the combiner must keep all state in class members because
173    the combiner's routines will be invoked for each signal
174    called. Compare, for example, a combiner that returns the maximum
175    element from calling the slots. If the maximum element ever
176    exceeds 100, no more slots are to be called.</p>
177<div class="informaltable"><table class="table">
178<colgroup>
179<col>
180<col>
181</colgroup>
182<thead><tr>
183<th align="left"><p>Pull</p></th>
184<th align="left"><p>Push</p></th>
185</tr></thead>
186<tbody><tr>
187<td align="left"><pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting">
188struct pull_max {
189  typedef int result_type;
190
191  template&lt;typename InputIterator&gt;
192  result_type operator()(InputIterator first,
193                         InputIterator last)
194  {
195    if (first == last)
196      throw std::runtime_error("Empty!");
197
198    int max_value = *first++;
199    while(first != last &amp;&amp; *first &lt;= 100) {
200      if (*first &gt; max_value)
201        max_value = *first;
202      ++first;
203    }
204
205    return max_value;
206  }
207};
208</pre></td>
209<td align="left"><pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting">
210struct push_max {
211  typedef int result_type;
212
213  push_max() : max_value(), got_first(false) {}
214
215  // returns false when we want to stop
216  bool operator()(int result) {
217    if (result &gt; 100)
218      return false;
219
220    if (!got_first) {
221      got_first = true;
222      max_value = result;
223      return true;
224    }
225
226    if (result &gt; max_value)
227      max_value = result;
228
229    return true;
230  }
231
232  int get_value() const
233  {
234    if (!got_first)
235      throw std::runtime_error("Empty!");
236    return max_value;
237  }
238
239private:
240  int  max_value;
241  bool got_first;
242};
243</pre></td>
244</tr></tbody>
245</table></div>
246<p>There are several points to note in these examples. The
247    "pull" version is a reusable function object that is based on an
248    input iterator sequence with an integer <code class="computeroutput">value_type</code>,
249    and is very straightforward in design. The "push" model, on the
250    other hand, relies on an interface specific to the caller and is
251    not generally reusable. It also requires extra state values to
252    determine, for instance, if any elements have been
253    received. Though code quality and ease-of-use is generally
254    subjective, the "pull" model is clearly shorter and more reusable
255    and will often be construed as easier to write and understand,
256    even outside the context of a signals &amp; slots library.</p>
257<p> The cost of the "pull" combiner interface is paid in the
258    implementation of the Signals library itself. To correctly handle
259    slot disconnections during calls (e.g., when the dereference
260    operator is invoked), one must construct the iterator to skip over
261    disconnected slots. Additionally, the iterator must carry with it
262    the set of arguments to pass to each slot (although a reference to
263    a structure containing those arguments suffices), and must cache
264    the result of calling the slot so that multiple dereferences don't
265    result in multiple calls. This apparently requires a large degree
266    of overhead, though if one considers the entire process of
267    invoking slots one sees that the overhead is nearly equivalent to
268    that in the "push" model, but we have inverted the control
269    structures to make iteration and dereference complex (instead of
270    making combiner state-finding complex).</p>
271</div>
272<div class="section" lang="en">
273<div class="titlepage"><div><div><h4 class="title">
274<a name="id2739833"></a>Connection Interfaces: +=  operator</h4></div></div></div>
275<p> Boost.Signals supports a connection syntax with the form
276    <code class="computeroutput">sig.<a href="../signalN.html#id2551390-bb">connect</a>(slot)</code>, but a
277    more terse syntax <code class="computeroutput">sig += slot</code> has been suggested (and
278    has been used by other signals &amp; slots implementations). There
279    are several reasons as to why this syntax has been
280    rejected:</p>
281<div class="itemizedlist"><ul type="disc">
282<li><p><span class="bold"><strong>It's unnecessary</strong></span>: the
283        connection syntax supplied by Boost.Signals is no less
284        powerful that that supplied by the <code class="computeroutput">+=</code>
285        operator. The savings in typing (<code class="computeroutput">connect()</code>
286        vs. <code class="computeroutput">+=</code>) is essentially negligible. Furthermore,
287        one could argue that calling <code class="computeroutput">connect()</code> is more
288        readable than an overload of <code class="computeroutput">+=</code>.</p></li>
289<li><p><span class="bold"><strong>Ambiguous return type</strong></span>:
290        there is an ambiguity concerning the return value of the
291        <code class="computeroutput">+=</code> operation: should it be a reference to the
292        signal itself, to enable <code class="computeroutput">sig += slot1 += slot2</code>,
293        or should it return a
294        <code class="computeroutput"><a href="../connection.html" title="Class connection">connection</a></code> for the
295        newly-created signal/slot connection?</p></li>
296<li>
297<p><span class="bold"><strong>Gateway to operators -=,
298        +</strong></span>: when one has added a connection operator
299        <code class="computeroutput">+=</code>, it seems natural to have a disconnection
300        operator <code class="computeroutput">-=</code>. However, this presents problems when
301        the library allows arbitrary function objects to implicitly
302        become slots, because slots are no longer comparable.  </p>
303<p> The second obvious addition when one has
304        <code class="computeroutput">operator+=</code> would be to add a <code class="computeroutput">+</code>
305        operator that supports addition of multiple slots, followed by
306        assignment to a signal. However, this would require
307        implementing <code class="computeroutput">+</code> such that it can accept any two
308        function objects, which is technically infeasible.</p>
309</li>
310</ul></div>
311</div>
312<div class="section" lang="en">
313<div class="titlepage"><div><div><h4 class="title">
314<a name="id2739993"></a><code class="computeroutput">trackable</code> rationale</h4></div></div></div>
315<div class="toc"><dl>
316<dt><span class="section"><a href="s06.html#id2740031"><code class="computeroutput">trackable</code> copying behavior</a></span></dt>
317<dt><span class="section"><a href="s06.html#id2740090">Why derivation from <code class="computeroutput">trackable</code>?</a></span></dt>
318</dl></div>
319<p> The <code class="computeroutput"><a href="../trackable.html" title="Class trackable">trackable</a></code>
320      class is the primary user interface to automatic connection
321      lifetime management, and its design affects users directly. Two
322      issues stick out most: the odd copying behavior of
323      <code class="computeroutput">trackable</code>, and the limitation requiring users to
324      derive from <code class="computeroutput">trackable</code> to create types that can
325      participate in automatic connection management.</p>
326<div class="section" lang="en">
327<div class="titlepage"><div><div><h5 class="title">
328<a name="id2740031"></a><code class="computeroutput">trackable</code> copying behavior</h5></div></div></div>
329<p> The copying behavior of
330      <code class="computeroutput"><a href="../trackable.html" title="Class trackable">trackable</a></code> is essentially
331      that <code class="computeroutput"><a href="../trackable.html" title="Class trackable">trackable</a></code> subobjects
332      are never copied; instead, the copy operation is merely a
333      no-op. To understand this, we look at the nature of a
334      signal-slot connection and note that the connection is based on
335      the entities that are being connected; when one of the entities
336      is destroyed, the connection is destroyed. Therefore, when a
337      <code class="computeroutput"><a href="../trackable.html" title="Class trackable">trackable</a></code> subobject is
338      copied, we cannot copy the connections because the connections
339      don't refer to the target entity - they refer to the source
340      entity. This reason is dual to the reason signals are
341      noncopyable: the slots connected to them are connected to that
342      particular signal, not the data contained in the signal.</p>
343</div>
344<div class="section" lang="en">
345<div class="titlepage"><div><div><h5 class="title">
346<a name="id2740090"></a>Why derivation from <code class="computeroutput">trackable</code>?</h5></div></div></div>
347<p> For <code class="computeroutput"><a href="../trackable.html" title="Class trackable">trackable</a></code> to work
348      properly, there are two constraints:</p>
349<div class="itemizedlist"><ul type="disc">
350<li><p><code class="computeroutput"><a href="../trackable.html" title="Class trackable">trackable</a></code> must
351          have storage space to keep track of all connections made to
352          this object.</p></li>
353<li><p><code class="computeroutput"><a href="../trackable.html" title="Class trackable">trackable</a></code> must be
354          notified when the object is being destructed so that it can
355          disconnect its connections.</p></li>
356</ul></div>
357<p>Clearly, deriving from
358      <code class="computeroutput"><a href="../trackable.html" title="Class trackable">trackable</a></code> meets these two
359      guidelines. We have not yet found a superior solution.</p>
360</div>
361</div>
362<div class="section" lang="en">
363<div class="titlepage"><div><div><h4 class="title">
364<a name="id2740156"></a>Comparison with other Signal/Slot implementations</h4></div></div></div>
365<div class="toc"><dl>
366<dt><span class="section"><a href="s06.html#id2740160">libsigc++</a></span></dt>
367<dt><span class="section"><a href="s06.html#id2740221">.NET delegates</a></span></dt>
368</dl></div>
369<div class="section" lang="en">
370<div class="titlepage"><div><div><h5 class="title">
371<a name="id2740160"></a>libsigc++</h5></div></div></div>
372<p><a href="http://libsigc.sourceforge.net" target="_top">libsigc++</a> is a C++
373      signals &amp; slots library that originally started as part of
374      an initiative to wrap the C interfaces to <a href="http://www.gtk.org" target="_top">GTK</a> libraries in C++, and has
375      grown to be a separate library maintained by Karl Nelson. There
376      are many similarities between libsigc++ and Boost.Signals, and
377      indeed Boost.Signals was strongly influenced by Karl Nelson and
378      libsigc++. A cursory inspection of each library will find a
379      similar syntax for the construction of signals and in the use of
380      connections and automatic connection lifetime management. There
381      are some major differences in design that separate these
382      libraries:</p>
383<div class="itemizedlist"><ul type="disc">
384<li><p><span class="bold"><strong>Slot definitions</strong></span>:
385          slots in libsigc++ are created using a set of primitives
386          defined by the library. These primitives allow binding of
387          objects (as part of the library), explicit adaptation from
388          the argument and return types of the signal to the argument
389          and return types of the slot (libsigc++ is, by default, more
390          strict about types than Boost.Signals). A discussion of this
391          approach with a comparison against the approach taken by
392          Boost.Signals is given in Choice of Slot Definitions.</p></li>
393<li><p><span class="bold"><strong>Combiner/Marshaller
394          interface</strong></span>: the equivalent to Boost.Signals
395          combiners in libsigc++ are the marshallers. Marshallers are
396          similar to the "push" interface described in Combiner
397          Interface, and a proper treatment of the topic is given
398          there.</p></li>
399</ul></div>
400</div>
401<div class="section" lang="en">
402<div class="titlepage"><div><div><h5 class="title">
403<a name="id2740221"></a>.NET delegates</h5></div></div></div>
404<p><a href="http://www.microsoft.com" target="_top">Microsoft</a>
405      has introduced the .NET Framework and an associated set of
406      languages and language extensions, one of which is the
407      delegate. Delegates are similar to signals and slots, but they
408      are more limited than most C++ signals and slots implementations
409      in that they:</p>
410<div class="itemizedlist"><ul type="disc">
411<li><p>Require exact type matches between a delegate and what
412          it is calling.</p></li>
413<li><p>Only return the result of the last target called, with no option for customization.</p></li>
414<li><p>Must call a method with <code class="computeroutput">this</code> already
415          bound.</p></li>
416</ul></div>
417</div>
418</div>
419</div>
420<table width="100%"><tr>
421<td align="left"><small><p>Last revised: July 20, 2004 at 17:03:55 GMT</p></small></td>
422<td align="right"><small>Copyright © 2001-2004 Douglas Gregor</small></td>
423</tr></table>
424<hr>
425<div class="spirit-nav">
426<a accesskey="p" href="s05.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../signals.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="tests.html"><img src="../images/next.png" alt="Next"></a>
427</div>
428</body>
429</html>
Note: See TracBrowser for help on using the repository browser.