Pseudo states

Page contents

Pseudo states are special kind of states that machine cannot enter, but they are useful to describe additional logic in machine behaviour.

Choice state

Choice state allows to select target state depending on some condition. When transition targeting a choice state is triggered, choice function is evaluated and machine goes to resulting state:

class SomeEvent(val value: Int) : Event

choiceState {
    when (event) {
        is SomeEvent -> { // cast is necessary as we don't know event type here
            if (someEvent.value > 3) State1 else State2
        }
        else -> { /*...*/
        }
    }
}

There is also choiceDataState() function available for choosing between DataStates of same type. You can define dataTransition to target such pseudo data state.

class IntEvent(override val data: Int) : DataEvent<Int>

lateinit var intState1: DataState<Int>
lateinit var intState2: DataState<Int>

createStateMachine(/*...*/) {
    // ...
    val choice = choiceDataState("data choice") {
        val intEvent = event as? IntEvent // cast is necessary as we don't know event type here
        if (intEvent?.data == 42) intState1 else intState2 // attempt of using state of other type will not compile
    }

    // here is a major reason to use choiceDataState(), to specify it as a target of dataTransition()
    dataTransition<IntEvent, Int> { targetState = choice }

    intState1 = dataState<Int>("intState1")
    intState2 = dataState<Int>("intState2")

}

You can use choiceState even on initial state branch. Note that choiceState can not be active, so if the library performs a transition and finds that choiceState is going to be activated, it executes its lambda argument and navigates to the resulting state. If the resulting state is also a PseudoState instance, further redirections might be applied.

History state

There are two types of history states, shallow and deep. Shallow history state is used to represent the most recently active child (its neighbour) of a parent state. It does not recurse into this child’s active configuration (sub states), initial states will be used. Deep history state in contrast reflects the most recent active configuration of the parent state (including all sub states). You can specify default state which will be used if history was not recorded yet (parent was not active). When default state is not specified, parent initial state will be entered on transition to history state.

val machine = createStateMachine(scope) {
    state {
        val state11 = initialState()
        val state12 = state()
        historyState(defultState = state12)
    }
    state {
        // ...
    }
}