Skip to content

Transitions

mikolaj-milewski edited this page Sep 19, 2024 · 10 revisions

Overview

Transition is the way to change state of State Machine.

In general, Transition consists of:

  • Trigger, type of Event that activates Transition,
  • Source, a State that transition is coming from,
  • Target, a State that transition is coming to,
  • Guard, logic that decides if Transition should happen,
  • Effect, logic that is run when Transition happens.

Types of Transitions

There are three types of Transitions:

  1. 'Regular' Transition that moves from one State to another,
  2. Internal Transition that has no Target State,
  3. Default Transition that has no explicit Trigger Event.

Transitions are always defined on the level of Source State.

Single State can have multiple Transitions triggered by various Event types. Moreover, there can be multiple Transitions triggered by the same Event type.

Definition

UML notation of Transition:

stateDiagram-v2
Source --> Target : Trigger [Guard] / Effect
Loading

Equivalent Stateflows notation of Transition:

Lambda style

    /* fragment of State Machine definition */
    .AddState("Source", b => b
        .AddTransition<Trigger>("Target", b => b
            .AddGuard(async c => true)
            .AddEffect(async c => {})
        )
    )
    .AddState("Target")

Typed style

    /* fragment of State Machine definition */
    .AddState<Source>(b => b
        .AddTransition<Trigger, TriggerTransition, Target>()
    )
    .AddState<Target>()

Using lambda style means that logic parts within Transition (Guard, Effect) are implemented directly in State Machine as lambdas. In typed style these logic parts are implemented in separate class.

Logic

There are two places where logic can be injected into Transition of any type, both optional:

  1. Guard:
    • determines if Transition should happen,
    • must return bool value,
    • lack of Guard on Transition means that there is an implicit true-returning Guard,
    • should not cause any side effect,
    • can be called multiple times on multiple Transitions, even the ones which won't eventually happen.
  2. Effect:
    • is called when Transition happens, after OnExit of Source State and before OnEntry of Target State,
    • can cause side effects.

The way of adding logic to Transition varies depending on used declaration style. For more details, refer to Guards or Effects, respectively.

Evaluation

When Event is sent to State Machine, Stateflows finds all Transitions triggered with this Event's type in current State's stack. Guards of these Transitions are then evaluated, one by one, and first Transition which Guard returns true is fired. That causes Source State to exit, Transition Effect is run, then Target State is entered.

Note that Internal Transition doesn't cause Source State to exit nor Target State to enter.

stateDiagram-v2
Source : Source<br/>/onExit
Source --> Target1 : Event1 [Guard1] / Effect2
Source --> Target2 : Event1 [Guard2] / Effect2
Target1 : Target1<br/>/onEntry
Target2 : Target2<br/>/onEntry
Loading

Let's consider above example:

  1. Current State of a State Machine is Source,
  2. Event Event1 is sent to a State Machine,
  3. Guard1 is evaluated, returns false,
  4. Guard2 is evaluated, returns true,
  5. Source's onExit is called,
  6. Effect2 is called,
  7. Target2's onEntry is called,
  8. Execution is complete with Target2 as new current State of a State Machine.

Else Transitions

When State contains multiple Transitions with various Guards, sometimes it is handy to use Else Transition - a Guard-less Transition which is fired when all other Transitions with the same Trigger fail to fire. Such Transition can be considered a fallback from all of these Transitions.

stateDiagram-v2
Source : Source<br/>/onExit
Source --> Target1 : Event1 [Guard1] / Effect2
Source --> Target2 : Event1 [Guard2] / Effect2
Source --> Target3 : Event1 [else] / Effect3
Target1 : Target1<br/>/onEntry
Target2 : Target2<br/>/onEntry
Target3 : Target3<br/>/onEntry
Loading

Let's consider above example:

  1. Current State of a State Machine is Source,
  2. Event Event1 is sent to a State Machine,
  3. Guard1 is evaluated, returns false,
  4. Guard2 is evaluated, returns false,
  5. Source's onExit is called,
  6. Effect3 is called,
  7. Target3's onEntry is called,
  8. Execution is complete with Target3 as new current State of a State Machine.

Else-ness of Transition is based on a Trigger type, not Transition type!

Nested States

Transitions defined on a higher nesting level of States structure are evaluated before more lower nesting level Transitions.

stateDiagram-v2
state State1 {
	Substate1 : Substate1<br/>/onExit
	Substate2 : Substate2<br/>/onEntry
	Substate1 --> Substate2 : Event1 / Effect1
}
State1 --> State2 : Event1
Loading

Let's consider above example:

  1. Current States of a State Machine are State1 / Substate1,
  2. Event Event1 is sent to a State Machine,
  3. Both available Transitions are Triggered by Event1, but inner Transition has precedence over outer Transition,
  4. Substate1's onExit is called,
  5. Effect1 is called,
  6. Substate2's onEntry is called,
  7. Execution is complete with State1 / Substate2 as new current States of a State Machine.
Clone this wiki locally