Boost logo

Boost Users :

From: Andreas Huber (ahd6974-spamgroupstrap_at_[hidden])
Date: 2005-07-21 08:03:09


Andreas Huber <ahd6974-spamgroupstrap <at> yahoo.com> writes:
> > I agree, but my impression is that the react function could be
> > implemented in any "outer context" which may not be the outmost one,
> > right?
>
> Hmmm, this never occurred to me. It would mean that you need to have
> something like the following
>
> struct RunningBase : sc::simple_state< RunningBase, ... >
> {
> virtual sc::result react( const EvX & ) { ... }
> };
>
> struct MyRunning : RunningBase
> {
> virtual sc::result react( const EvX & ) { ... }
> };
>
> and then inside some inner state of RunningBase:
>
> struct Inner : sc::simple_state< Inner, RunningBase >
> {
> typedef sc::custom_reaction< EvX > reactions;
>
> sc::result react( const EvX & evt )
> {
> // depending on the requirements for the transition
> // (is it ok to exit and maybe reenter RunningBase),
> // we'd maybe also need to pass *this to react
> context< RunningBase >().react( evt );
> }
> };
>
> I've never tried but I don't see anything that would keep you from doing
> this. I can't currently think of a good example where this technique
> would make sense, please let me know if you find one!

I just realized that the above only works in a very limited way:

1. History transitions *never* go back to the MyRunning state, they always go
to the RunningBase state.
2. When calling state_base::dynamic_type() on a const state_base & referencing
a MyRunning state object, a value identifying MyRunning is returned *only*
*if* BOOST_STATECHART_USE_NATIVE_RTTI is defined. Otherwise, a value
identifying RunningBase is returned. Even worse, MyRunning::static_type()
*always* returns a value identifying RunningBase.
3. MyRunning::custom_static_type_ptr() sets custom type information for
RunningBase, there's no way to define it for MyRunning.
4. There is no way for MyRunning to define additional reactions or replace
some of those defined in RunningBase.
5. There is no way for MyRunning to define or replace inner initial states
defined by RunningBase.

There are probably more drawbacks looming, but IMO the list above is more than
enough to stay away from this technique. It is therefore a good idea to always
pass the "the most-derived subtype" of the simple_state class template as its
first template parameter (as currently documented in the reference).

However, something similar to the above is still possible without any of the
drawbacks by making RunningBase a template:

struct Inner;
// There possibly more template parameters...
template< class MostDerived >
struct RunningBase : sc::simple_state< MostDerived, Inner >
{
  typedef MostDerived RunningState;
};

struct Running : RunningBase< Running >
{
  sc::result react( const EvX & )
  {
    // ...
  }
};

struct MyRunning : RunningBase< MyRunning >
{
  sc::result react( const EvX & )
  {
    // ...
  }
};

struct Inner : sc::simple_state< Inner, RunningBase >
{
  typedef sc::custom_reaction< EvX > reactions;

  sc::result react( const EvX & evt )
  {
    context< RunningState >().react( evt );
  }
};

This has the added benefit of no longer requiring a virtual function...

-- 
Andreas Huber 
When replying by private email, please remove the words spam and trap 
from the address shown in the header.

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net