statemachine
statemachine copied to clipboard
Default transition / run-to-completion
Is there a way to define default transition (transition without a trigger, which activates automatically on completion of incoming event)? That would allow to run more complex logic in run-to-completion approach.
I don't understand what you try to accomplish. What do you mean by "completion of incoming event"?
Can you give an example?
Let's consider state machine:
(o)--->( State_1 )--- Event_1 --->( State_2 )--->( State_3 )
State_1 is initial one. Machine receives Event_1 and transits to State_2. State_2 has an outgoing transition without any event specified as trigger, so it transits to State_3 immediatelly.
This is not how I understood run to completion mode (see https://en.wikipedia.org/wiki/UML_state_machine#Run-to-completion_execution_model)
You could mimic this behaviour by firing a priority event in the entry action. Works only for passive state machines though.
I know this behavior from IBM Rhapsody which calls it 'null transitions' (www.ibm.com/support/knowledgecenter/SSB2MU_8.1.5/com.ibm.rhp.uml.diagrams.doc/topics/rhp_t_dm_using_null_trans.html). It has a counterpart on UML State Machine called 'completion transition' (http://www-01.ibm.com/support/docview.wss?uid=swg27040251, http://www-sop.inria.fr/members/Charles.Andre/CAdoc/ESINSA/Chap7-StateMachine.pdf).
I've managed to mimic this by sending agreed 'completion event' on extension's method FiredEvent() - works well on passive state machine, haven't tested on active though.
I guess we could add something like this:
machine.In(States.A)
.Goto(States.B)
Just a Goto
without an On
that specifies the event.
It does not compile on 4.4.0 nor 5.0.0-pre0003.
This is an idea. And it is not yet implemented.
Okay, now I got it. I don't think it will be enough - this transition should have guards and actions as any other.
Yes of course. After the Goto
it would be possible to add guards and actions. The addition is that it would be possible to "skip" the On
.
I'm really short of time to work on this, maybe you could provide a pull request for this? If you have questions, I can still help.
Adding If
's and Execute
's after the Goto
seems counterintuitive for me - I'd like to guard the transition itself, not only execution of action. Maybe adding specific function to indicate completion transition would be better? For example:
machine.In('a').Continue().If(() => true).Goto('b')
Regarding If
after Goto
- I've done some tests and it seems erroneous for me. I'll file another issue.
Yes, you are right, I mixed that up.
The order of the configuration parts is always like this:
machine.In.On.If.Goto.Execute
And I like your idea of using Continue
because it makes it much clearer that we immediately forward to another state.
Any supported way to achieve this in the current version? I tried creating an extension, but IStateMachineInformation
does not expose any way to fire an event.
My workaround is this:
public static class StateMachineExtensions
{
public static void SetNullTransitions<TState, TEvent>(this IStateMachine<TState, TEvent> machine, TEvent nullTransition, params TState[] states) where TState : IComparable where TEvent : IComparable
{
machine.TransitionCompleted += (s, a) => { if (states.Contains(a.NewStateId)) machine.FirePriority(nullTransition); };
}
}
Of course you still need to define the null transition itself on each state involved.
Hello @ursenzler , are there any plans to implement this? Anything I can do to assist? This seems like a nice solution to a few of my current problems.
@ComtelJeremy I have no plans for this state machine 😱 It is my hobby project and I only add things that I need myself. I simply don't have the time for more.
But in case you provide a Pull Request, I'll gladly answer your questions, review it and merge it if possible.
I also struggle still a bit with this idea. The reason is that the "state" that is immediately left is not a real state (a state that the state machine resides in). However, if the addition of "Continue" has no negative side-effects on the existing functionality, I won't block it.
@ursenzler Thank you for letting me know. Any guidance on where best to put this functionality if I write a PR? I'm just starting to get familiar with your code. Nice work!
As for the concept, perhaps this use case would help you understand my need (or you could point me in a better direction)... I am using a state to clean up resources (dispose them), update the UI, and then loop back to the initial state or to a completed state based on a guard clause. I think that (very briefly entered) state is needed since many other branches use it as their endpoint and not all of them are entered (guard clauses).
I'm currently using this workaround: comment.
Please notice that there are two state machines in the code: the one supporting async and the one without support for async. I think it is best to first get the async machine running with the new functionality. It is easier to port the changes from the async to the non-async machine than vice-versa.
I would start with writing a spec/test that shows how the new functionality should work. To make that compile, I'd extend the syntax. Getting the syntax work can sometimes be a bit tricky. The difficult part is where the logic for the continue should be placed in the state machine. I'm unsure where it would be best.
But here is probably a good candidate that could work: StateMachine directly after executing a transition (https://github.com/appccelerate/statemachine/blob/6ae943467fca0472887aefeeeb9d387cb17354f4/source/Appccelerate.StateMachine/AsyncMachine/StateMachine.cs#L153). The result should probably indicate that we need to "continue". The information that we should continue can be obtained here:
- StateLogic calling the transition https://github.com/appccelerate/statemachine/blob/6ae943467fca0472887aefeeeb9d387cb17354f4/source/Appccelerate.StateMachine/AsyncMachine/States/StateLogic.cs#L64
- TransitionLogic that knows the actually executed transition and has access to its definition https://github.com/appccelerate/statemachine/blob/6ae943467fca0472887aefeeeb9d387cb17354f4/source/Appccelerate.StateMachine/AsyncMachine/Transitions/TransitionLogic.cs#L95
I hope this gives you a good start!
You can open a PR even before making any changes and with incomplete changes. This makes helping easier because I can comment directly in your code.