Boost logo

Boost Users :

From: Felipe Magno de Almeida (felipe.m.almeida_at_[hidden])
Date: 2008-06-24 21:15:09


On Tue, Jun 24, 2008 at 4:57 PM, Andreas Huber
<ahd6974-spamboostorgtrap_at_[hidden]> wrote:
> "Felipe Magno de Almeida" <felipe.m.almeida_at_[hidden]> wrote in message

[snip]

>> struct Z : sc::simple_state<Y, Z>
>> {
>> Z(int, int);
>> };
>>
>> struct Y : sc::simple_state<Y, X, Z>
>> {
>> Y() : sc::simple_state(inner_state_arguments(0,1))
>> {}
>> };
>
> IIUC, then Y as defined above would require that all its inner states have a
> constructor with two integer parameters. I think this is too limiting.

The naming is confusing, but I meant only the inner initial state Z.

[snip]

> I'm not sure I understand. How are the constructors "fixed" with the factory
> approach I suggested? How are they not fixed with other approaches?

My idea is that different transit calls could call different constructors with
different arguments.

struct A : sc::simple_state<A, machine>
{
  A(int);
  A(int, int);
};

struct B : sc::simple_state<B, machine>
{
  typedef sc::custom_reaction<event1> reactiotns;
  sc::result react(event1 const&) { return transit<A>(5); }
};

struct C : sc::simple_state<C, machine>
{
  typedef sc::custom_reaction<event1> reactions;
  sc::result react(event1 const&) { return transit<A>(6, 7); }
};

quoting the other email:

>> Actually, I have myself an use case for passing arguments to outer states.
>>
>> I'm just throwing here a suggestion:
>> How about having another way of transiting in this case?
>>
>> cascate_transit<state1>(inner_arg1, inner_arg2)
>> .outer<state2>(middle_arg1, middle_arg2)
>> .outer<state3>(outer_arg1, middle_arg2);
>
> Something in this direction could work. With .outer you mean to imply that
> state2 is a direct outer state of state1, right? What if state2 doesn't
> require any ctor parameters but state3 does? Also, here's a somewhat
> esoteric but IMO still not unreasonable case:

I wanted that empty constructors could be implicit, so if it wanted
to call state2 with an empty constructor, then it wouldn't be needed
to call .outer<state2>. And an empty call to outer<statex>() should
be defined as calling the default constructor.
Should this be too hard?

> <http://www.boost.org/doc/libs/1_35_0/libs/statechart/doc/CameraWithHistory2.gif>
>
> In the transition triggered by EvShutterReleased, it is clear that we're
> entering NotShooting but it's not clear whether we will enter Idle or
> Configuring (this depends on which of the two was active when we last left
> NotShooting). IMO, you should be able to supply ctor parameters for none,
> one or even both of the inner states of NotShooting.
>
> At this point I think it is kind of obvious that there's no point in
> enforcing an order of supplying ctor arguments. We need a map that
> associates a type with a construction function, with no particular order of
> map entries. Exactly how said map should look like and how it is constructed
> is not yet clear to me. I hope I'll find the time to toy around a little
> bit.

I'm not sure if a map is helpful. What we really need, IMHO, is a way
that reactions can construct dictate how state transition is going to be.
Not only from a static typing POV, but as dynamic data as well.
That's why I have focused on transit<> until now.
I see that your example is related to history. Isn't it more related to
how the state was, rather than how the state will be?
I understand that *if needed* (as much as in my case for construction
of outer states) people should be able to pass arguments for all states
in the chain. But where someone doesn't matter, the states should
be restored.
So I think that my cascate_transit would do fine here too.
IMHO, a transition is always specific, and anything that wouldn't
allow different transitions to pass different arguments to different
constructors of the same state in whichever reaction is not enough.
Even the same reaction function should be able to transit to different
state values for the same state type.
I want this for example:

struct A : sc::simple_state<A, machine>
{
  int i;
  A(int i) : i(i) {}
};

struct B : sc::simple_state<B, machine>
{
  typedef sc::custom_reaction<event1> reactions;
  sc::result reac(event1 const& e)
  {
    return transit<A>(e.value);
  }
};

>> And completely off-topic:
>> Also, a state that is instantiated through tss (when multithreaded),
>> or through a
>> global variable (when single-threaded) could be good.
>
> I don't think I understand. Could you elaborate a little bit on this one?

It might not be worth because states are completely templated, and
that could generate too much global points, though that can be
alleviated with downcasting and upcasting the context.
but let me show:

struct A : sc::auto_state<A, machine>
{
  A()
  {
    context<machine>().process_event(event1());
  }
};

the code that does the initialization for auto_state would be
something like this:

boost::thread_specific_ptr<context> global_auto_state_context;

template <typename ....>
struct initialization_trick : state<...>
{
  initialization_trick()
    : state<...>(global_auto_state_context.reset())
  {}
};

template <typename ....>
struct auto_state : initialization_trick<...>
{

};

template <typename State>
State* construct_state()
{
  global_auto_state_context.reset(new context(arg1, arg2));
  return new State;
}

Since the bases are going to be initialized before everything else,
we can guarantee there won't be problems.

> Regards,
>
> --
> Andreas Huber

Regards,

-- 
Felipe Magno de Almeida

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