From 39411a966df033c54b6c6d971acb9361ad27943e Mon Sep 17 00:00:00 2001 From: "rodrigo.nogueira" Date: Thu, 25 Dec 2025 22:09:30 -0300 Subject: [PATCH] docs: Clarify conditional transition evaluation order Addresses issue #541 by clarifying that conditional transitions are evaluated in declaration order (when state.to() is called), not in the order they appear when combined with the | operator. Changes: - Update description to explicitly mention "declaration order" - Add Important note box with clear examples showing: - How declaration order differs from composition order - Common pitfall where variable names don't match check order - Correct way to control evaluation order This documentation fix helps prevent user confusion about which transition will be checked first when using multiple conditional transitions for the same event. Closes #541 --- docs/guards.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/docs/guards.md b/docs/guards.md index 54cce66c..da050a14 100644 --- a/docs/guards.md +++ b/docs/guards.md @@ -22,7 +22,37 @@ A conditional transition occurs only if specific conditions or criteria are met. When a transition is conditional, it includes a condition (also known as a _guard_) that must be satisfied for the transition to take place. If the condition is not met, the transition does not occur, and the state machine remains in its current state or follows an alternative path. -This feature allows for multiple transitions on the same {ref}`event`, with each {ref}`transition` checked in the order they are declared. A condition acts like a predicate (a function that evaluates to true/false) and is checked when a {ref}`statemachine` handles an {ref}`event` with a transition from the current state bound to this event. The first transition that meets the conditions (if any) is executed. If none of the transitions meet the conditions, the state machine either raises an exception or does nothing (see the `allow_event_without_transition` parameter of {ref}`StateMachine`). +This feature allows for multiple transitions on the same {ref}`event`, with each {ref}`transition` checked in **declaration order** — that is, the order in which the transitions themselves were created using `state.to()`. A condition acts like a predicate (a function that evaluates to true/false) and is checked when a {ref}`statemachine` handles an {ref}`event` with a transition from the current state bound to this event. The first transition that meets the conditions (if any) is executed. If none of the transitions meet the conditions, the state machine either raises an exception or does nothing (see the `allow_event_without_transition` parameter of {ref}`StateMachine`). + +```{important} +**Evaluation order is based on declaration order, not composition order.** + +When using conditional transitions, the order of evaluation is determined by **when each transition was created** (the order of `state.to()` calls), **not** by the order they appear when combined with the `|` operator. + +For example: + +```python +# These are evaluated in DECLARATION ORDER (when state.to() was called): +last_checked = state_a.to(state_x) # Created FIRST → Checked FIRST +mid_checked = state_a.to(state_y) # Created SECOND → Checked SECOND +first_checked = state_a.to(state_z) # Created THIRD → Checked THIRD + +# The | operator does NOT change evaluation order: +my_event = first_checked | mid_checked | last_checked +# Evaluation order is still: last_checked → mid_checked → first_checked +``` + +To control the evaluation order, declare transitions in the desired order: + +```python +# Declare in the order you want them checked: +first = state_a.to(state_b, cond="check1") # Checked FIRST +second = state_a.to(state_c, cond="check2") # Checked SECOND +third = state_a.to(state_d, cond="check3") # Checked THIRD + +my_event = first | second | third # Order matches declaration +``` +``` When {ref}`transitions` have guards, it is possible to define two or more transitions for the same {ref}`event` from the same {ref}`state`. When the {ref}`event` occurs, the guarded transitions are checked one by one, and the first transition whose guard is true will be executed, while the others will be ignored.