I'm wondering if it would be useful to provide a way to have guards be kept out of the state machine, to keep it all "pure function".
The way I thought it might work would be to add a parameter to the transition
to specify the value of any guards. The guards would always be optional, but would of course influence the outcome. Here's a machine with a named guard (I use 'guard' instead of 'cond' because I like statechart terminology better than scxml):
m = Machine({
foo: {
on: {
A: bar,
B: {
target: bar
guard: isEmpty
}
}
},
bar: {}
})
var object = []
direct = transition(m.initialState, 'A'); // transitions directly to bar, as before
guarded = transition(m.initialState, 'A'); // about to transition from foo to bar, but it was guarded.
guarded.missingGuards; // [ "isEmpty" ]
failure = transition(m.initialState, 'A', { isEmpty: false }); // state is still "foo" — the event was basically not handled.
success = transition(m.initialState, 'A', { isEmpty: true }); // state is "bar" as the guard allowed the transition to happen.
A successful state transition requires that you verify that missingGuards
is empty. If there are any missingGuards
then you need to retry the state transition providing those missing guards. The missingGuards
would be a property on the State object returned.
The third parameter to transition would be somewhat of a bitset with the names of the guards and their boolean values.
The guard
attribute should allow boolean logic, though, so that it's possible to say guard: "!isEmpty && ready"
in the machine definition, and that this would require the isEmpty
and ready
guards to be provided.
Well, order does matter, and I feel that's a rather contrived example.
It's a bit like saying that boolean logic i flawed because you might write stupid stuff like
if (isEmpty && somethingElse && isEmpty)
— Yes, the lastisEmpty
is redundant :).These guards are the if tests of statecharts, and we should spend time getting them right, that's for sure :)