[MSM] Unable to retrieve correct value of attribute of a state from within actions. (Possible Bug?)
Hi everyone,
Hi Christophe,
Using Boost.MSM with eUML I tried to access the attribute of a state
from within an action.
However, the value is not what I expected when accessing the attribute
of the state given as argument to the action. (It seems to be the
default-parameter.) If I access the state directly (by name) and
retrieve the value from it, it is set correctly as expected.
Could it be that an action gets its arguments as copies? If so, I guess,
the attributes of the copied arguments should be copied, too.
This is the case for events. The attributes of an event given to the
action seems to be set correctly.
But the attributes of a state seem to be default-initialized.
For clarification a simple example (this time tested and successfully
compiled):
#include <iostream>
#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
#include
Hi Deniz,
Using Boost.MSM with eUML I tried to access the attribute of a state from within an action. However, the value is not what I expected when accessing the attribute of the state given as argument to the action. (It seems to be the default-parameter.) If I access the state directly (by name) and retrieve the value from it, it is set correctly as expected.
Could it be that an action gets its arguments as copies?
No, unless there is a recent bug, but I really don't think so. Copies in MSM are something we want to avoid for performance reasons.
// The attribute: BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int, Number) BOOST_MSM_EUML_ATTRIBUTES((attributes_ << Number), NumberAttr) // An event containing the attribute: BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(event1, NumberAttr) // Two states with attributes: BOOST_MSM_EUML_STATE((no_action, no_action, attributes_ << Number), state1) BOOST_MSM_EUML_STATE((no_action, no_action, attributes_ << Number), state2)
// Entry-action which initializes the attributes: BOOST_MSM_EUML_ACTION(init_events_and_states) { template
void operator()(Evt const&, Fsm&, State&) { event1.get_attribute(Number) = 100; state1.get_attribute(Number) = 1; state2.get_attribute(Number) = 2; }; };
Ouch! I admit I didn't think about this use case. This is what happens when
an author tries to hide implementation details ;-)
event1, state1 and state2 are really just "lies".
eUML is simply some syntactic sugar on top of the functor front-end. These
variables are only here because in the review, several people complained
that you had to write in the stt something like State1() + Event1() ==
State2().
state1 simply is a dummy variable, all I want from it is its type. Of
course, one instance exists, but normally, one does not care.
So, there is no copy but msm takes the type of state1 and create its own
instance (though you still have the possibility to copy from an already
existing instance).
What you are allowed to use are the template parameters: source state,
target state, event, and fsm (on which, if you call fsm. template
get_state
fsm.process_event(event1); // this really is event1!
As you can see, the attribute-values of "event1" and "evt" are the same. However, the attribute-values of "state1" and "source" differ although they should be the same, too. (The same applies to "state2" and "target".)
As you process event1, you really are changing the dummy instance, so you get the same as if you used the event in the action. Normally, you shouldn't care because events are temporary variables. I don't recommend using this trick ;-) States differ, as explained above. I hope I could clarify this. Cheers, Christophe
Hi Christophe,
// The attribute: BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int, Number) BOOST_MSM_EUML_ATTRIBUTES((attributes_ << Number), NumberAttr) // An event containing the attribute: BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(event1, NumberAttr) // Two states with attributes: BOOST_MSM_EUML_STATE((no_action, no_action, attributes_ << Number), state1) BOOST_MSM_EUML_STATE((no_action, no_action, attributes_ << Number), state2)
// Entry-action which initializes the attributes: BOOST_MSM_EUML_ACTION(init_events_and_states) { template
void operator()(Evt const&, Fsm&, State&) { event1.get_attribute(Number) = 100; state1.get_attribute(Number) = 1; state2.get_attribute(Number) = 2; }; }; Ouch! I admit I didn't think about this use case. This is what happens when an author tries to hide implementation details ;-) event1, state1 and state2 are really just "lies". eUML is simply some syntactic sugar on top of the functor front-end. These variables are only here because in the review, several people complained that you had to write in the stt something like State1() + Event1() == State2(). state1 simply is a dummy variable, all I want from it is its type. Of course, one instance exists, but normally, one does not care. [snip] So, there is no copy but msm takes the type of state1 and create its own instance (though you still have the possibility to copy from an already existing instance).
Thank you, that clarifies a lot.
What you are allowed to use are the template parameters: source state, target state, event, and fsm (on which, if you call fsm. template get_state
() will give you a reference to the real state1).
You are missing a '&' or '*' behind the macro, but you are right, that does what I wanted in the first place.
fsm.process_event(event1); // this really is event1!
[snip] As you process event1, you really are changing the dummy instance, so you get the same as if you used the event in the action. Normally, you shouldn't care because events are temporary variables. I don't recommend using this trick ;-)
Just for final clarification three more questions: 1. You mean, that from within the "operator()" of an action I am only allowed to use the parameters for accessing states, events, and the FSM internals? (Neither "event_", "source_", "target_", "fsm_", nor accessing the dummy-instances directly.) This is now clear for the current event, current source- and target state as well as for all other states of the FSM (by accessing them with "get_state"). 2. However, how to access other events than the current one? It seems to work as I did before (by accessing the "dummy"-instance of the event), but if you do not recommend it, maybe there is a better solution? (I need to access all events directly to initialize their event-number attributes from within the FSM's entry-action.) 3. And all the underscore-accessors "event_", "source_", "target_", "fsm_" are only allowed to be used from within the transition table? Maybe you could emphasize the real usage in the documentation, so that nobody misuses it (like I did). Thanks, Deniz
Hi Deniz,
Just for final clarification three more questions:
1. You mean, that from within the "operator()" of an action I am only allowed to use the parameters for accessing states, events, and the FSM internals? (Neither "event_", "source_", "target_", "fsm_", nor accessing the dummy-instances directly.)
I didn't say this, just the dummy states you declare for the table. If you had this declared: BOOST_MSM_EUML_METHOD(ActivateEmpty_ , activate_empty , activate_empty_ , void , void ) You could call inside a state action something like: activate_empty_(target_)(evt,fsm,*this); or inside an action: activate_empty_(target_)(evt,fsm,src,target); But the interest is quite limited. They are made for the transition table. But as you see, msm creates some valid functors.
This is now clear for the current event, current source- and target state as well as for all other states of the FSM (by accessing them with "get_state").
2. However, how to access other events than the current one?
It seems to work as I did before (by accessing the "dummy"-instance of the event), but if you do not recommend it, maybe there is a better solution? (I need to access all events directly to initialize their event-number attributes from within the FSM's entry-action.)
Well, you could do this for events. Though as you seem to have a number for every type, a static member could be easier. The normal way is usually in the event constructor but I agree that for eUML, it is not so practical, so yes, your trick will do.
3. And all the underscore-accessors "event_", "source_", "target_", "fsm_" are only allowed to be used from within the transition table?
They are allowed everywhere but their main reason of existence is to make a nicer transition table.
Maybe you could emphasize the real usage in the documentation, so that nobody misuses it (like I did).
Ok, will do. Thanks. Cheers, Christophe
Hi Christophe,
1. You mean, that from within the "operator()" of an action I am only allowed to use the parameters for accessing states, events, and the FSM internals? (Neither "event_", "source_", "target_", "fsm_", nor accessing the dummy-instances directly.)
I didn't say this, just the dummy states you declare for the table. If you had this declared:
BOOST_MSM_EUML_METHOD(ActivateEmpty_ , activate_empty , activate_empty_ , void , void )
You could call inside a state action something like:
activate_empty_(target_)(evt,fsm,*this);
or inside an action:
activate_empty_(target_)(evt,fsm,src,target);
But the interest is quite limited. They are made for the transition table. But as you see, msm creates some valid functors.
It seems I was a little unclear with formulating my question. I assumed using "event_", "source_", "target_" and "fsm_" for accessing an attribute from within an action is not allowed. However, there seems to be no real reason for using them in this way, because one could as well use the corresponding action-parameter and its "get_attribute" member-function.
This is now clear for the current event, current source- and target state as well as for all other states of the FSM (by accessing them with "get_state").
2. However, how to access other events than the current one?
It seems to work as I did before (by accessing the "dummy"-instance of the event), but if you do not recommend it, maybe there is a better solution? (I need to access all events directly to initialize their event-number attributes from within the FSM's entry-action.)
Well, you could do this for events. Though as you seem to have a number for every type, a static member could be easier. The normal way is usually in the event constructor but I agree that for eUML, it is not so practical, so yes, your trick will do.
You are right. I would have preferred to use the event's constructor, but on the other side, I also prefer using your macros. :-) But ok, for events that does not seem to be a problem.
3. And all the underscore-accessors "event_", "source_", "target_", "fsm_" are only allowed to be used from within the transition table?
They are allowed everywhere but their main reason of existence is to make a nicer transition table.
And using them for accessing attributes seems to work only reliably in the transition table (at least for states). But that's fine, as one can use "get_attribute" from within actions.
Maybe you could emphasize the real usage in the documentation, so that nobody misuses it (like I did).
Ok, will do. Thanks.
Thank you a lot for all this clarification and especially for this great library. It helps me a lot. Ciao, Deniz
participants (2)
-
Christophe Henry
-
Deniz Bahadir