Open x37v opened 2 years ago
I think my confusion around guards is because transitioning from the same state, with the same event but different guards isn't legal:
statemachine! {
transitions: {
*State1 + Event1(MyEventData) [guard1] / action1 = State2,
State1 + Event1(MyEventData) [guard2] / action1 = State4,
}
}
but if you look at the boost action-guards example you can see that in their setup, it would be:
...
, "s3"_s + event<e4> [ !guard1 || guard2 ] / (action1, [] { std::cout << "action3" << std::endl; }) = "s4"_s
, "s3"_s + event<e4> [ guard1 ] / ([] { std::cout << "action4" << std::endl; }, [this] { action4(); } ) = "s5"_s
...
@x37v, I looked at both of your comments and would like to summarize the 3 options you touch on.
The issue I see here will be around error checking. The main reason to NOT allow 2 transitions with the same starting state and event and different guards is that if both guards are true, you can have can have a transition table with a conflicting output state. Given that this crate was originally designed to mimic the boost syntax, I think it makes sense to mimic it where features overlap. This syntax basically allows for an event to be re-used with different logical combinations of guards, forcing the user to explicitly specify a mutually exclusive transition.
The main reason to NOT allow 2 transitions with the same starting state and event and different guards is that if both guards are true, you can have can have a transition table with a conflicting output state.
Yeah.. I have a fork that allows for this and there is an implicit behavior that the first valid transition takes precedence (as it is just a match
)
@x37v, why not do a PR? Its new syntax that is useful that is a user is not required to use.
I do think the Rust style match guard is the most elegant approach, although definitely not what boost uses.
@x37v, why not do a PR? Its new syntax that is useful that is a user is not required to use.
it is quite a departure: https://github.com/x37v/smlang-rs
Multiple transitions with same state/event combination but different guards is important for versatility. Otherwise a user needs to expand what a guard could handle into separate events, which can lead to code duplication.
the README states:
But in the examples we see that guards return
Result<(), ()>
.. functionally I guess they're the same except I see that you can return a custom error instead of()
. But, re my question below, depending on the goal of a guard, anErr(())
might feel a little wrong?I'm wondering what the general idea for a guard is? I'm assuming it is a way to encapsulate some functionality so that
Event
data can be evaluated and instead of havingButtonSevenDown
you can haveButton { down: true, index: 7 }
and evaluate the a guardbutton_down
,button_seven_down
orbutton_seven
?