• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2
3<html>
4<head>
5  <meta http-equiv="Content-Language" content="en-us">
6  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
7  <meta name="GENERATOR" content="Microsoft FrontPage 6.0">
8  <meta name="ProgId" content="FrontPage.Editor.Document">
9  <link rel="stylesheet" type="text/css" href="../../../boost.css">
10
11  <title>The Boost Statechart Library - Rationale</title>
12</head>
13
14<body link="#0000FF" vlink="#800080">
15  <table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
16  "header">
17    <tr>
18      <td valign="top" width="300">
19        <h3><a href="../../../index.htm"><img alt="C++ Boost" src=
20        "../../../boost.png" border="0" width="277" height="86"></a></h3>
21      </td>
22
23      <td valign="top">
24        <h1 align="center">The Boost Statechart Library</h1>
25
26        <h2 align="center">Rationale</h2>
27      </td>
28    </tr>
29  </table>
30  <hr>
31
32  <dl class="index">
33    <dt><a href="#Introduction">Introduction</a></dt>
34
35    <dt><a href="#WhyYetAnotherStateMachineFramework">Why yet another state
36    machine framework</a></dt>
37
38    <dt><a href="#StateLocalStorage">State-local storage</a></dt>
39
40    <dt><a href="#DynamicConfigurability">Dynamic configurability</a></dt>
41
42    <dt><a href="#ErrorHandling">Error handling</a></dt>
43
44    <dt><a href="#AsynchronousStateMachines">Asynchronous state
45    machines</a></dt>
46
47    <dt><a href="#MemberFunctionsVsFunctionObjects">User actions: Member
48    functions vs. function objects</a></dt>
49
50    <dt><a href="#Limitations">Limitations</a></dt>
51  </dl>
52
53  <h2><a name="Introduction" id="Introduction">Introduction</a></h2>
54
55  <p>Most of the design decisions made during the development of this library
56  are the result of the following requirements.</p>
57
58  <p>Boost.Statechart should ...</p>
59
60  <ol>
61    <li>be fully type-safe. Whenever possible, type mismatches should be
62    flagged with an error at compile-time</li>
63
64    <li>not require the use of a code generator. A lot of the existing FSM
65    solutions force the developer to design the state machine either
66    graphically or in a specialized language. All or part of the code is then
67    generated</li>
68
69    <li>allow for easy transformation of a UML statechart (defined in
70      <a href="http://www.omg.org/cgi-bin/doc?formal/03-03-01">http://www.omg.org/cgi-bin/doc?formal/03-03-01</a>)
71      into a working state machine. Vice versa, an existing C++
72      implementation of a state machine should be fairly trivial to transform
73      into a UML statechart. Specifically, the following state machine
74      features should be supported:
75
76      <ul>
77        <li>Hierarchical (composite, nested) states</li>
78
79        <li>Orthogonal (concurrent) states</li>
80
81        <li>Entry-, exit- and transition-actions</li>
82
83        <li>Guards</li>
84
85        <li>Shallow/deep history</li>
86      </ul>
87    </li>
88
89    <li>produce a customizable reaction when a C++ exception is propagated
90    from user code</li>
91
92    <li>support synchronous and asynchronous state machines and leave it to
93    the user which thread an asynchronous state machine will run in. Users
94    should also be able to use the threading library of their choice</li>
95
96    <li>support the development of arbitrarily large and complex state
97    machines. Multiple developers should be able to work on the same state
98    machine simultaneously</li>
99
100    <li>allow the user to customize all resource management so that the
101    library could be used for applications with hard real-time
102    requirements</li>
103
104    <li>enforce as much as possible at compile time. Specifically, invalid
105    state machines should not compile</li>
106
107    <li>offer reasonable performance for a wide range of applications</li>
108  </ol>
109
110  <h2><a name="WhyYetAnotherStateMachineFramework" id=
111  "WhyYetAnotherStateMachineFramework">Why yet another state machine
112  framework?</a></h2>
113
114  <p>Before I started to develop this library I had a look at the following
115  frameworks:</p>
116
117  <ul>
118    <li>The framework accompanying the book "Practical Statecharts in C/C++"
119    by Miro Samek, CMP Books, ISBN: 1-57820-110-1<br>
120    <a href=
121    "http://www.quantum-leaps.com">http://www.quantum-leaps.com<br></a> Fails
122    to satisfy at least the requirements 1, 3, 4, 6, 8.</li>
123
124    <li>The framework accompanying "Rhapsody in C++" by ILogix (a code
125    generator solution)<br>
126    <a href=
127    "http://www.ilogix.com/sublevel.aspx?id=53">http://www.ilogix.com/sublevel.aspx?id=53<br>
128    </a> This might look like comparing apples with oranges. However, there
129    is no inherent reason why a code generator couldn't produce code that can
130    easily be understood and modified by humans. Fails to satisfy at least
131    the requirements 2, 4, 5, 6, 8 (there is quite a bit of error checking
132    before code generation, though).</li>
133
134    <li>The framework accompanying the article "State Machine Design in
135    C++"<br>
136    <a href=
137    "http://www.ddj.com/184401236?pgno=1">http://www.ddj.com/184401236?pgno=1<br>
138    </a> Fails to satisfy at least the requirements 1, 3, 4, 5 (there is no
139    direct threading support), 6, 8.</li>
140  </ul>
141
142  <p>I believe Boost.Statechart satisfies all requirements.</p>
143
144  <h2><a name="StateLocalStorage" id="StateLocalStorage">State-local
145  storage</a></h2>
146
147  <p>This not yet widely known state machine feature is enabled by the fact
148  that every state is represented by a class. Upon state-entry, an object of
149  the class is constructed and the object is later destructed when the state
150  machine exits the state. Any data that is useful only as long as the
151  machine resides in the state can (and should) thus be a member of the
152  state. This feature paired with the ability to spread a state machine over
153  several translation units makes possible virtually unlimited
154  scalability.&nbsp;</p>
155
156  <p>In most existing FSM frameworks the whole state machine runs in one
157  environment (context). That is, all resource handles and variables local to
158  the state machine are stored in one place (normally as members of the class
159  that also derives from some state machine base class). For large state
160  machines this often leads to the class having a huge number of data members
161  most of which are needed only briefly in a tiny part of the machine. The
162  state machine class therefore often becomes a change hotspot what leads to
163  frequent recompilations of the whole state machine.</p>
164
165  <p>The FAQ item "<a href="faq.html#StateLocalStorage">What's so cool about
166  state-local storage?</a>" further explains this by comparing the tutorial
167  StopWatch to a behaviorally equivalent version that does not use
168  state-local storage.</p>
169
170  <h2><a name="DynamicConfigurability" id="DynamicConfigurability">Dynamic
171  configurability</a></h2>
172
173  <h3>Two types of state machine frameworks</h3>
174
175  <ul>
176    <li>A state machine framework supports dynamic configurability if the
177    whole layout of a state machine can be defined at runtime ("layout"
178    refers to states and transitions, actions are still specified with normal
179    C++ code). That is, data only available at runtime can be used to build
180    arbitrarily large machines. See "<a href=
181    "https://www.researchgate.net/publication/293741100_A_multiple_substring_search_algorithm">A
182    Multiple Substring Search Algorithm</a>" by Moishe Halibard and Moshe Rubin
183    in June 2002 issue of CUJ for a good example.
184
185    <li>On the other side are state machine frameworks which require the
186    layout to be specified at compile time</li>
187  </ul>
188
189  <p>State machines that are built at runtime almost always get away with a
190  simple state model (no hierarchical states, no orthogonal states, no entry
191  and exit actions, no history) because the layout is very often <b>computed
192  by an algorithm</b>. On the other hand, machine layouts that are fixed at
193  compile time are almost always designed by humans, who frequently need/want
194  a sophisticated state model in order to keep the complexity at acceptable
195  levels. Dynamically configurable FSM frameworks are therefore often
196  optimized for simple flat machines while incarnations of the static variant
197  tend to offer more features for abstraction.</p>
198
199  <p>However, fully-featured dynamic FSM libraries do exist. So, the question
200  is:</p>
201
202  <h3>Why not use a dynamically configurable FSM library for all state
203  machines?</h3>
204
205  <p>One might argue that a dynamically configurable FSM framework is all one
206  ever needs because <b>any</b> state machine can be implemented with it.
207  However, due to its nature such a framework has a number of disadvantages
208  when used to implement static machines:</p>
209
210  <ul>
211    <li>No compile-time optimizations and validations can be made. For
212    example, Boost.Statechart determines the <a href=
213    "definitions.html#InnermostCommonContext">innermost common context</a> of
214    the transition-source and destination state at compile time. Moreover,
215    compile time checks ensure that the state machine is valid (e.g. that
216    there are no transitions between orthogonal states).</li>
217
218    <li>Double dispatch must inevitably be implemented with some kind of a
219    table. As argued under <a href="performance.html#DoubleDispatch">Double
220    dispatch</a>, this scales badly.</li>
221
222    <li>To warrant fast table lookup, states and events must be represented
223    with an integer. To keep the table as small as possible, the numbering
224    should be continuous, e.g. if there are ten states, it's best to use the
225    ids 0-9. To ensure continuity of ids, all states are best defined in the
226    same header file. The same applies to events. Again, this does not
227    scale.</li>
228
229    <li>Because events carrying parameters are not represented by a type,
230    some sort of a generic event with a property map must be used and
231    type-safety is enforced at runtime rather than at compile time.</li>
232  </ul>
233
234  <p>It is for these reasons, that Boost.Statechart was built from ground up
235  to <b>not</b> support dynamic configurability. However, this does not mean
236  that it's impossible to dynamically shape a machine implemented with this
237  library. For example, guards can be used to make different transitions
238  depending on input only available at runtime. However, such layout changes
239  will always be limited to what can be foreseen before compilation. A
240  somewhat related library, the boost::spirit parser framework, allows for
241  roughly the same runtime configurability.</p>
242
243  <h2><a name="ErrorHandling" id="ErrorHandling">Error handling</a></h2>
244
245  <p>There is not a single word about error handling in the UML state machine
246  semantics specifications. Moreover, most existing FSM solutions also seem
247  to ignore the issue.&nbsp;</p>
248
249  <h3>Why an FSM library should support error handling</h3>
250
251  <p>Consider the following state configuration:</p>
252
253  <p><img alt="A" src="A.gif" border="0" width="230" height="170"></p>
254
255  <p>Both states define entry actions (x() and y()). Whenever state A becomes
256  active, a call to x() will immediately be followed by a call to y(). y()
257  could depend on the side-effects of x(). Therefore, executing y() does not
258  make sense if x() fails. This is not an esoteric corner case but happens in
259  every-day state machines all the time. For example, x() could acquire
260  memory the contents of which is later modified by y(). There is a different
261  but in terms of error handling equally critical situation in the Tutorial
262  under <a href=
263  "tutorial.html#GettingStateInformationOutOfTheMachine">Getting state
264  information out of the machine</a> when <code>Running::~Running()</code>
265  accesses its outer state <code>Active</code>. Had the entry action of
266  <code>Active</code> failed and had <code>Running</code> been entered anyway
267  then <code>Running</code>'s exit action would have invoked undefined
268  behavior. The error handling situation with outer and inner states
269  resembles the one with base and derived classes: If a base class
270  constructor fails (by throwing an exception) the construction is aborted,
271  the derived class constructor is not called and the object never comes to
272  life.<br>
273  In most traditional FSM frameworks such an error situation is relatively
274  easy to tackle <b>as long as the error can be propagated to the state
275  machine client</b>. In this case a failed action simply propagates a C++
276  exception into the framework. The framework usually does not catch the
277  exception so that the state machine client can handle it. Note that, after
278  doing so, the client can no longer use the state machine object because it
279  is either in an unknown state or the framework has already reset the state
280  because of the exception (e.g. with a scope guard). That is, by their
281  nature, state machines typically only offer basic exception safety.<br>
282  However, error handling with traditional FSM frameworks becomes
283  surprisingly cumbersome as soon as a lot of actions can fail and the state
284  machine <b>itself</b> needs to gracefully handle these errors. Usually, a
285  failing action (e.g. x()) then posts an appropriate error event and sets a
286  global error variable to true. Every following action (e.g. y()) first has
287  to check the error variable before doing anything. After all actions have
288  completed (by doing nothing!), the previously posted error event has to be
289  processed what leads to the execution of the remedy action. Please note
290  that it is not sufficient to simply queue the error event as other events
291  could still be pending. Instead, the error event has absolute priority and
292  has to be dealt with immediately. There are slightly less cumbersome
293  approaches to FSM error handling but these usually necessitate a change of
294  the statechart layout and thus obscure the normal behavior. No matter what
295  approach is used, programmers are normally forced to write a lot of code
296  that deals with errors and most of that code is <b>not</b> devoted to error
297  handling but to error propagation.</p>
298
299  <h3>Error handling support in Boost.Statechart</h3>
300
301  <p>C++ exceptions may be propagated from any action to signal a failure.
302  Depending on how the state machine is configured, such an exception is
303  either immediately propagated to the state machine client or caught and
304  converted into a special event that is dispatched immediately. For more
305  information see the <a href="tutorial.html#ExceptionHandling">Exception
306  handling</a> chapter in the Tutorial.</p>
307
308  <h3>Two stage exit</h3>
309
310  <p>An exit action can be implemented by adding a destructor to a state. Due
311  to the nature of destructors, there are two disadvantages to this
312  approach:</p>
313
314  <ul>
315    <li>Since C++ destructors should virtually never throw, one cannot simply
316    propagate an exception from an exit action as one does when any of the
317    other actions fails</li>
318
319    <li>When a <code>state_machine&lt;&gt;</code> object is destructed then
320    all currently active states are inevitably also destructed. That is,
321    state machine termination is tied to the destruction of the state machine
322    object</li>
323  </ul>
324
325  <p>In my experience, neither of the above points is usually problem in
326  practice since ...</p>
327
328  <ul>
329    <li>exit actions cannot often fail. If they can, such a failure is
330    usually either
331
332      <ul>
333        <li>not of interest to the outside world, i.e. the failure can simply
334        be ignored</li>
335
336        <li>so severe, that the application needs to be terminated anyway. In
337        such a situation stack unwind is almost never desirable and the
338        failure is better signaled through other mechanisms (e.g.
339        abort())</li>
340      </ul>
341    </li>
342
343    <li>to clean up properly, often exit actions <b>must</b> be executed when
344    a state machine object is destructed, even if it is destructed as a
345    result of a stack unwind</li>
346  </ul>
347
348  <p>However, several people have put forward theoretical arguments and
349  real-world scenarios, which show that the exit action to destructor mapping
350  <b>can</b> be a problem and that workarounds are overly cumbersome. That's
351  why <a href="tutorial.html#TwoStageExit">two stage exit</a> is now
352  supported.</p>
353
354  <h2><a name="AsynchronousStateMachines" id=
355  "AsynchronousStateMachines">Asynchronous state machines</a></h2>
356
357  <h3>Requirements</h3>
358
359  <p>For asynchronous state machines different applications have rather
360  varied requirements:</p>
361
362  <ol>
363    <li>In some applications each state machine needs to run in its own
364    thread, other applications are single-threaded and run all machines in
365    the same thread</li>
366
367    <li>For some applications a FIFO scheduler is perfect, others need
368    priority- or EDF-schedulers</li>
369
370    <li>For some applications the boost::thread library is just fine, others
371    might want to use another threading library, yet other applications run
372    on OS-less platforms where ISRs are the only mode of (apparently)
373    concurrent execution</li>
374  </ol>
375
376  <h3>Out of the box behavior</h3>
377
378  <p>By default, <code>asynchronous_state_machine&lt;&gt;</code> subtype
379  objects are serviced by a <code>fifo_scheduler&lt;&gt;</code> object.
380  <code>fifo_scheduler&lt;&gt;</code> does not lock or wait in
381  single-threaded applications and uses boost::thread primitives to do so in
382  multi-threaded programs. Moreover, a <code>fifo_scheduler&lt;&gt;</code>
383  object can service an arbitrary number of
384  <code>asynchronous_state_machine&lt;&gt;</code> subtype objects. Under the
385  hood, <code>fifo_scheduler&lt;&gt;</code> is just a thin wrapper around an
386  object of its <code>FifoWorker</code> template parameter (which manages the
387  queue and ensures thread safety) and a
388  <code>processor_container&lt;&gt;</code> (which manages the lifetime of the
389  state machines).</p>
390
391  <p>The UML standard mandates that an event not triggering a reaction in a
392  state machine should be silently discarded. Since a
393  <code>fifo_scheduler&lt;&gt;</code> object is itself also a state machine,
394  events destined to no longer existing
395  <code>asynchronous_state_machine&lt;&gt;</code> subtype objects are also
396  silently discarded. This is enabled by the fact that
397  <code>asynchronous_state_machine&lt;&gt;</code> subtype objects cannot be
398  constructed or destructed directly. Instead, this must be done through
399  <code>fifo_scheduler&lt;&gt;::create_processor&lt;&gt;()</code> and
400  <code>fifo_scheduler&lt;&gt;::destroy_processor()</code>
401  (<code>processor</code> refers to the fact that
402  <code>fifo_scheduler&lt;&gt;</code> can only host
403  <code>event_processor&lt;&gt;</code> subtype objects;
404  <code>asynchronous_state_machine&lt;&gt;</code> is just one way to
405  implement such a processor). Moreover,
406  <code>create_processor&lt;&gt;()</code> only returns a
407  <code>processor_handle</code> object. This must henceforth be used to
408  initiate, queue events for, terminate and destroy the state machine through
409  the scheduler.</p>
410
411  <h3>Customization</h3>
412
413  <p>If a user needs to customize the scheduler behavior she can do so by
414  instantiating <code>fifo_scheduler&lt;&gt;</code> with her own class
415  modeling the <code>FifoWorker</code> concept. I considered a much more
416  generic design where locking and waiting is implemented in a policy but I
417  have so far failed to come up with a clean and simple interface for it.
418  Especially the waiting is a bit difficult to model as some platforms have
419  condition variables, others have events and yet others don't have any
420  notion of waiting whatsoever (they instead loop until a new event arrives,
421  presumably via an ISR). Given the relatively few lines of code required to
422  implement a custom <code>FifoWorker</code> type and the fact that almost
423  all applications will implement at most one such class, it does not seem to
424  be worthwhile anyway. Applications requiring a less or more sophisticated
425  event processor lifetime management can customize the behavior at a more
426  coarse level, by using a custom <code>Scheduler</code> type. This is
427  currently also true for applications requiring non-FIFO queuing schemes.
428  However, Boost.Statechart will probably provide a
429  <code>priority_scheduler</code> in the future so that custom schedulers
430  need to be implemented only in rare cases.</p>
431
432  <h2><a name="MemberFunctionsVsFunctionObjects" id=
433  "MemberFunctionsVsFunctionObjects">User actions: Member functions vs.
434  function objects</a></h2>
435
436  <p>All user-supplied functions (<code>react</code> member functions,
437  entry-, exit- and transition-actions) must be class members. The reasons
438  for this are as follows:</p>
439
440  <ul>
441    <li>The concept of state-local storage mandates that state-entry and
442    state-exit actions are implemented as members</li>
443
444    <li><code>react</code> member functions and transition actions often
445    access state-local data. So, it is most natural to implement these
446    functions as members of the class the data of which the functions will
447    operate on anyway</li>
448  </ul>
449
450  <h2><a name="Limitations" id="Limitations">Limitations</a></h2>
451
452  <h4>Junction points</h4>
453
454  <p>UML junction points are not supported because arbitrarily complex guard
455  expressions can easily be implemented with
456  <code>custom_reaction&lt;&gt;</code>s.</p>
457
458  <h4>Dynamic choice points</h4>
459
460  <p>Currently there is no direct support for this UML element because its
461  behavior can often be implemented with
462  <code>custom_reaction&lt;&gt;</code>s. In rare cases this is not possible,
463  namely when a choice point happens to be the initial state. Then, the
464  behavior can easily be implemented as follows:</p>
465  <pre>
466struct make_choice : sc::event&lt; make_choice &gt; {};
467
468// universal choice point base class template
469template&lt; class MostDerived, class Context &gt;
470struct choice_point : sc::state&lt; MostDerived, Context &gt;
471{
472  typedef sc::state&lt; MostDerived, Context &gt; base_type;
473  typedef typename base_type::my_context my_context;
474  typedef choice_point my_base;
475
476  choice_point( my_context ctx ) : base_type( ctx )
477  {
478    this-&gt;post_event( boost::intrusive_ptr&lt; make_choice &gt;(
479      new make_choice() ) );
480  }
481};
482
483// ...
484
485struct MyChoicePoint;
486struct Machine : sc::state_machine&lt; Machine, MyChoicePoint &gt; {};
487
488struct Dest1 : sc::simple_state&lt; Dest1, Machine &gt; {};
489struct Dest2 : sc::simple_state&lt; Dest2, Machine &gt; {};
490struct Dest3 : sc::simple_state&lt; Dest3, Machine &gt; {};
491
492struct MyChoicePoint : choice_point&lt; MyChoicePoint, Machine &gt;
493{
494  MyChoicePoint( my_context ctx ) : my_base( ctx ) {}
495
496  sc::result react( const make_choice &amp; )
497  {
498    if ( /* ... */ )
499    {
500      return transit&lt; Dest1 &gt;();
501    }
502    else if ( /* ... */ )
503    {
504      return transit&lt; Dest2 &gt;();
505    }
506    else
507    {
508      return transit&lt; Dest3 &gt;();
509    }
510  }
511};
512</pre>
513
514  <p><code>choice_point&lt;&gt;</code> is not currently part of
515  Boost.Statechart, mainly because I fear that beginners could use it in
516  places where they would be better off with
517  <code>custom_reaction&lt;&gt;</code>. If the demand is high enough I will
518  add it to the library.</p>
519
520  <h4>Deep history of orthogonal regions</h4>
521
522  <p>Deep history of states with orthogonal regions is currently not
523  supported:</p>
524
525  <p><img alt="DeepHistoryLimitation1" src="DeepHistoryLimitation1.gif"
526  border="0" width="331" height="346"></p>
527
528  <p>Attempts to implement this statechart will lead to a compile-time error
529  because B has orthogonal regions and its direct or indirect outer state
530  contains a deep history pseudo state. In other words, a state containing a
531  deep history pseudo state must not have any direct or indirect inner states
532  which themselves have orthogonal regions. This limitation stems from the
533  fact that full deep history support would be more complicated to implement
534  and would consume more resources than the currently implemented limited
535  deep history support. Moreover, full deep history behavior can easily be
536  implemented with shallow history:</p>
537
538  <p><img alt="DeepHistoryLimitation2" src="DeepHistoryLimitation2.gif"
539  border="0" width="332" height="347"></p>
540
541  <p>Of course, this only works if C, D, E or any of their direct or indirect
542  inner states do not have orthogonal regions. If not so then this pattern
543  has to be applied recursively.</p>
544
545  <h4>Synchronization (join and fork) bars</h4>
546
547  <p><img alt="JoinAndFork" src="JoinAndFork.gif" border="0" width="541"
548  height="301"></p>
549
550  <p>Synchronization bars are not supported, that is, a transition always
551  originates at exactly one state and always ends at exactly one state. Join
552  bars are sometimes useful but their behavior can easily be emulated with
553  guards. The support of fork bars would make the implementation <b>much</b>
554  more complex and they are only needed rarely.</p>
555
556  <h4>Event dispatch to orthogonal regions</h4>
557
558  <p>The Boost.Statechart event dispatch algorithm is different to the one
559  specified in <a href=
560  "http://www.wisdom.weizmann.ac.il/~dharel/SCANNED.PAPERS/Statecharts.pdf">David
561  Harel's original paper</a> and in the <a href=
562  "http://www.omg.org/cgi-bin/doc?formal/03-03-01">UML standard</a>. Both
563  mandate that each event is dispatched to all orthogonal regions of a state
564  machine. Example:</p>
565
566  <p><img alt="EventDispatch" src="EventDispatch.gif" border="0" width="436"
567  height="211"></p>
568
569  <p>Here the Harel/UML dispatch algorithm specifies that the machine must
570  transition from (B,D) to (C,E) when an EvX event is processed. Because of
571  the subtleties that Harel describes in chapter 7 of <a href=
572  "http://www.wisdom.weizmann.ac.il/~dharel/SCANNED.PAPERS/Statecharts.pdf">his
573  paper</a>, an implementation of this algorithm is not only quite complex
574  but also much slower than the simplified version employed by
575  Boost.Statechart, which stops searching for <a href=
576  "definitions.html#Reaction">reactions</a> as soon as it has found one
577  suitable for the current event. That is, had the example been implemented
578  with this library, the machine would have transitioned
579  non-deterministically from (B,D) to either (C,D) or (B,E). This version was
580  chosen because, in my experience, in real-world machines different
581  orthogonal regions often do not specify transitions for the same events.
582  For the rare cases when they do, the UML behavior can easily be emulated as
583  follows:</p>
584
585  <p><img alt="SimpleEventDispatch" src="SimpleEventDispatch.gif" border="0"
586  width="466" height="226"></p>
587
588  <h4>Transitions across orthogonal regions</h4>
589
590  <p><img alt="TransAcrossOrthRegions" src="TransAcrossOrthRegions.gif"
591  border="0" width="226" height="271"></p>
592
593  <p>Transitions across orthogonal regions are currently flagged with an
594  error at compile time (the UML specifications explicitly allow them while
595  Harel does not mention them at all). I decided to not support them because
596  I have erroneously tried to implement such a transition several times but
597  have never come across a situation where it would make any sense. If you
598  need to make such transitions, please do let me know!</p>
599  <hr>
600
601  <p><a href="http://validator.w3.org/check?uri=referer"><img border="0" src=
602  "../../../doc/images/valid-html401.png" alt="Valid HTML 4.01 Transitional"
603  height="31" width="88"></a></p>
604
605  <p>Revised
606  <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->03 December, 2006<!--webbot bot="Timestamp" endspan i-checksum="38512" --></p>
607
608  <p><i>Copyright &copy; 2003-<!--webbot bot="Timestamp" s-type="EDITED" s-format="%Y" startspan -->2006<!--webbot bot="Timestamp" endspan i-checksum="770" -->
609  <a href="contact.html">Andreas Huber D&ouml;nni</a></i></p>
610
611  <p><i>Distributed under the Boost Software License, Version 1.0. (See
612  accompanying file <a href="../../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or
613  copy at <a href=
614  "http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</a>)</i></p>
615</body>
616</html>
617