appccelerate / statemachine

A .net library that lets you build state machines (hierarchical, async with fluent definition syntax and reporting capabilities).
Apache License 2.0
481 stars 128 forks source link

Call superstate executes for the same event as the child is in #65

Open muisje opened 4 years ago

muisje commented 4 years ago

Currently the super states won't react to an event fired. Is there any elegant way to have all the super states of the current states be called on the same event if it is defined like that?

so for instance i have this function that is defined for every state. I want it to be called for every superstate including the current state: builder.In(state).On(Events.Do).Execute(state.Do); but it only executes for the current state and not the super states when firing the event Do,

ursenzler commented 4 years ago

A transition on a superstate is only called when there is no transition lower in the hierarchy that matches the event and its guard returns true.

I suggest that you add the action to be executed in the transition actions lower in the hierarchy.

muisje commented 4 years ago

Yeah, but how do you know what the super states are?

I've looked it doing it with extensions at the firing event but I'm unable to see what the super state is. Maybe i don't get it, but i like to access https://github.com/appccelerate/statemachine/blob/master/source/Appccelerate.StateMachine/Machine/States/IStateDefinition.cs because there i can see what the super state is. And the events and actions. Like that i could just do recursively for each super state call the action which has the same event.

I cannot do it in a pretty way either at definition since i can't access the hierarchy when building the state machine.

The least favorable way to do this is having an hierarchy defined as a copy, but I don't think that that is a great solution.

Do you've any other suggestions or am i understanding somethings not correctly?

ursenzler commented 4 years ago

I see only the way to do this, but as I understood you, that is what you want to prevent:

(pseudo code) DefineHierarchyOn(Superstate).WithInitialSubState(A).AndChildren(B);

In(SuperState).On(E).Execute(Action); In(A).On(E).Execute(Action, AnotherAction) In(B).On(E).Execute(Action, YetAnotherAction)

or call Action from inside AnotherAction and YetAnotherAction.

I thought about adding a possibility to specify whether a transition should be passed from superstates to its children, but I don't really like that idea. I think that calling the action explicitly, makes the state machine easier to understand.

muisje commented 4 years ago

So what I thought would work before you told me that the deepest event would get fired on duplicate event:

In(SuperState).On(E).Execute(Action); In(A).On(E).Execute(Action, AnotherAction); In(B).On(E).Execute(Action, YetAnotherAction);

I think that is pretty explicit. And you could maybe in the define hierarchy choose then what behaviour you want on duplicate event. So by default it would only call the lowest in hierarchy (to preserve backwards compatibility) and if you do define it would call all actions in the hierarchy on the event.

And the second option sounds less favorable to me when using it, because you do have to know which other actions you need to call in the sub state actions.

ursenzler commented 4 years ago

As I understand your idea, it wouldn't work. I understand that you assume that transitions in super states for the same event would have the same target state. However, that is not true. A child state could point to Foo, a superstate to Bar. Please correct me if I didn't understand your idea.