# Nested States

The UML2 specification allows for the concept of a nested state.

Nested states exist to reduce exponential 'state' and 'transition' explosions that can occur with classic FSMs.

Let's look at a code example and the associated diagram.

```dart
 var machine = StateMachine.create((g) => g
    ..initialState<S>()
    ..state<Alive>((b) => b
      ..onEnter((s, e) => print('onEnter $s as a result of $e'))
      ..onExit((s, e) => print('onExit $s as a result of $e'))
      ..on<OnBirthday, Young>(condition: (s, e) => human.age < 18, sideEffect: () => human.age++)
      ..on<OnBirthday, MiddleAged>(condition: (s, e) => human.age < 50, sideEffect: () => human.age++)
      ..on<OnBirthday, Old>(condition: (s, e) => human.age < 80, sideEffect: () => human.age++)
      ..on<OnDeath, Dead>()
      ..state<Young>((b) => b)
      ..state<MiddleAged>((b) => b)
      ..state<Old>((b) => b))
    ..state<Dead>((b) => b
      ..on<OnGood, Budist>(condition: (s, e) => s == Dead)
      ..on<OnUgly, SalvationArmy>(condition: (s, e) => s == InHell)
      ..on<OnBad, Christian>(condition: (s, e) => s == InHeaven)
      ..state<InHeaven>((b) => b..state<Budist>((b) => b))
      ..state<InHell>((b) => b..state<Christian>((b) => b..state<Catholic>((b) => b)..state<SalvationArmy>((b) => b))))
    ..onTransition((td) => watcher.log('${td.eventType}')));

```

In the above code block the indentations show the level of nesting.  You can see that the state 'Young' is nested within the state 'Alive'.

![](/files/-MMTem6gf0Ydp0hnxawG)

Each box represents a State and its nested states. In the above diagram we have two top level states 'Alive' and 'Dead'.

You can see how the 'Young' state is nested within the 'Alive' state box which reflects the above code.

There is no limit to the depth of nesting.

## Leaf States

States that have no child states of their own are referred to as Leaf States.&#x20;

{% hint style="info" %}
When looking at a nested state diagram, the top state(s) are the root state(s) and any states that are at the end of a branch are the leaf states. So in the above diagram Alive and Dead a root states and Buddhist and Old are leaf states.
{% endhint %}

*Due to the limits of the dot diagraming tooling (or my ability to use it) the grey ovals are duplicates of the box. The State  'Alive' is also represented by a box and the grey oval 'Alive'. This is done so that transitions to the parent state can be easily represented on the diagram.*

## Abstract States

When you create a nested set of states any states that have children states becomes 'abstract' states.

{% hint style="warning" %}
You cannot transition to an abstract state!
{% endhint %}

In the above example each of 'the Alive', 'Dead', 'InHeavan', 'InHell' and 'Christian' states have children states and are therefore abstract states.

It is only valid to create a transition to a Leaf state.&#x20;

## A Nested FSM can be in multiple states!

When an FSM is in a Nested State we say that it is also in ALL ancestor states.

A classic FSM can only ever be in a single state, Nested States make life more interesting >:) \*2

As an example; if the above FSM transitions to the 'Catholic' state we say that the FSM is in the 'Catholic' state,  'InHell' state and the 'Dead' state simultaneously.

If you call StateMachine.isInState\<Dead>() or StateMachine.isInState\<InHell>() both will return true.

## Cascading Events

If a parent state has a transition then we say that the child state also has that transition.

Let's look at a toaster oven that supports toasting and baking and that turns off the heater when the door is open.\*1

```dart
StateMachine _createMachine() {
  return StateMachine.create((g) => g
    ..initialState<DoorOpen>()
    ..state<DoorOpen>((b) {})
    ..state<Toasting>((b) => b
            // one
           ..on<OpenDoor, DoorOpen>())
    ..state<Baking>((b) => b
            // and duplicate
           ..on<OpenDoor, DoorOpen>())
  )); 
}
```

In the above example the transition ..on\<OpenDoor, DoorOpen> is duplicated for both the Toasting and Baking state.

If we create a super state `Heating` we can then make it the parent of `Toasting` and `Baking` .&#x20;

We can now  attached the  .on\<OpenDoor, DoorOpen> transition to the `Heating` state.

Both Toasting and Baking now inherit the .on\<OpenDoor, DoorOpen> transition from the Heating state.

This is the result:

```dart
StateMachine _createMachine() {
  return StateMachine.create((g) => g
    ..initialState<DoorOpen>()
    ..state<DoorOpen>((b) {})
    // new super state
    ..state<Heating>((b) => b
      // transition shared by heating, toasting and baking.
      ..on<OpenDoor, DoorOpen>()
      ..state<Toasting>((b) {})
      ..state<Baking>((b) {}))); 
}
```

This may not seem much of a saving but when you have an FSM with a significant no. of States and events then Nested States significantly reduce the complexity of an FSM.

\*1 Example sourced from: <https://www.embedded.com/a-crash-course-in-uml-state-machines-part-2/>

\*2 Evil grin


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://fsm2.onepub.dev/states/nested-states.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
