Boost logo

Boost :

From: Alexander Nasonov (alnsn_at_[hidden])
Date: 2005-02-10 13:49:20


Jonathan,
/* I'm replying to you privately because I don't have access to my private
 * mailbox from work and apparently I don't want to publish my business
 * address on internet. As soon as I get home I'll post it to boost list.
 */

Jonathan Turkanis wrote:
> What I would like to know is why you want to represent overload sets as
> compile-time collections: what sort of computations can you do with them
in
> practice? I'm not expressing any scepticism that it's useful, I just want
more
> information.

Ok. Using state machine as an example:

struct Fsm
{
    Running operator()( id<1>, Passive, EvActivate ) const;
    Stopped operator()( id<2>, Running, EvStartStop ) const;
    Running operator()( id<3>, Stopped, EvStartStop ) const;
    Stopped operator()( id<4>, Active, EvReset ) const;
    // ...
};

Every call operator has such pattern:

    NewState operator()(id<N>, State, Event) const;

and represents a transition from a state State to a state NewState caused by
event Event. Transition logic is defined in the call operator body.
If you were using MPL containers you would need to implement the logic in
separate functions and pass them along the lines of metainformation about
FSM:

// 1. Runtime part of information about transitions:
Running activate(Passive,EvActivate);
Stopped stop(Running,EvStartStop);
Running start(Stopped,EvStartStop);
Stopped reset(Active,EvReset);

// 2. Compile-time part of information about transitions:
typedef mpl::vector<
      transition<Running(Passive,EvActivate), &activate>
    , transition<Stopped(Running,EvStartStop), &stop>
    , transition<Running(Stopped,EvStartStop),&start>
    , transition<Stopped(Active,EvReset),&reset>
> transitions;

// 3. FSM generator:
fsm<transitions,Passive> m; // initial state is Passive

// 4. Go
m.processEvent(EvActivate());
// ...

Most interesing part here is FSM generator. Using the power of MPL and
type_traits, it gets states out of transitions, allocates storage for them
and generates transition table. Additionally, it could take into account
inheritance relashionship between states to allow superstates/substates or
it could treat void return type as no transition (action only) or it could
discard transitions under certain circumstances or it could turn thrown
exception into event and process it or ... A lot of interesting things are
possible, thanks to MPL and other boost libraries :)
My library is supposed to do same things. The difference is that step 1 and
2 are now not separated and you don't have to scroll up and down to make
sure both parts are in sync.

// 1. Runtime part of information about transitions is in Fsm's body
// 2. Compile-time part of information about transitions is
overloads::set<Fsm>
struct Fsm
{
    Running operator()( id<1>, Passive, EvActivate ) const;
    Stopped operator()( id<2>, Running, EvStartStop ) const;
    Running operator()( id<3>, Stopped, EvStartStop ) const;
    Stopped operator()( id<4>, Active, EvReset ) const;
    // ...
};

// 3. FSM generator:
fsm<Fsm,Passive> m; // initial state is Passive

// 4. Go
m.processEvent(EvActivate());
// ...

Hope this helps,

--
Alexander Nasonov

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk