summaryrefslogtreecommitdiff
path: root/doc/html/signals/s06.html
blob: 03b96f17c41619f1f30a30e4a08693beb82d0796 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<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.78.1">
<link rel="home" href="../index.html" title="The Boost C++ Libraries BoostBook Documentation Subset">
<link rel="up" href="../signals.html" title="Chapter&#160;27.&#160;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="idm45555132851264"></a>Design Rationale</h2></div></div></div>
<div class="toc"><dl class="toc">
<dt><span class="section"><a href="s06.html#idm45555132850288">Choice of Slot Definitions</a></span></dt>
<dt><span class="section"><a href="s06.html#idm45555132840432">User-level Connection Management</a></span></dt>
<dt><span class="section"><a href="s06.html#idm45555132822128">Combiner Interface</a></span></dt>
<dt><span class="section"><a href="s06.html#idm45555132807040">Connection Interfaces: +=  operator</a></span></dt>
<dt><span class="section"><a href="s06.html#idm45555132787664"><code class="computeroutput">trackable</code> rationale</a></span></dt>
<dt><span class="section"><a href="s06.html#idm45555132767552">Comparison with other Signal/Slot implementations</a></span></dt>
</dl></div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="idm45555132850288"></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" style="list-style-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="idm45555132840432"></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" style="list-style-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#idm45506985002448-bb">connect</a>(slot)</code> is
        performed via
        <code class="computeroutput">sig.<a class="link" href="../boost/signalN.html#idm45506982619872-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#idm45506982619872-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" style="list-style-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="idm45555132822128"></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 &amp; slots
    libraries, the combiners are unfortunately not reusable (either in
    other signals &amp; 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&lt;typename InputIterator&gt;
  result_type operator()(InputIterator first,
                         InputIterator last)
  {
    if (first == last)
      throw std::runtime_error("Empty!");

    int max_value = *first++;
    while(first != last &amp;&amp; *first &lt;= 100) {
      if (*first &gt; 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 &gt; 100)
      return false;

    if (!got_first) {
      got_first = true;
      max_value = result;
      return true;
    }

    if (result &gt; 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 &amp; 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="idm45555132807040"></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#idm45506985002448-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 &amp; slots implementations). There
    are several reasons as to why this syntax has been
    rejected:</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-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="idm45555132787664"></a><code class="computeroutput">trackable</code> rationale</h3></div></div></div>
<div class="toc"><dl class="toc">
<dt><span class="section"><a href="s06.html#idm45555132783040"><code class="computeroutput">trackable</code> copying behavior</a></span></dt>
<dt><span class="section"><a href="s06.html#idm45555132776880">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="idm45555132783040"></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="idm45555132776880"></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" style="list-style-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="idm45555132767552"></a>Comparison with other Signal/Slot implementations</h3></div></div></div>
<div class="toc"><dl class="toc">
<dt><span class="section"><a href="s06.html#idm45555132766848">libsigc++</a></span></dt>
<dt><span class="section"><a href="s06.html#idm45555132759504">.NET delegates</a></span></dt>
</dl></div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="idm45555132766848"></a>libsigc++</h4></div></div></div>
<p> <a href="http://libsigc.sourceforge.net" target="_top">libsigc++</a> is a C++
      signals &amp; 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" style="list-style-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="idm45555132759504"></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" style="list-style-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"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 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>