# Flow Modifiers

> Atomic, serial, parallel and oneof blocks in FizzBee: how each controls execution and where yield points let other actions interleave.

Canonical: https://fizzbee.io/reference/language/flow-modifiers/
Source: https://github.com/fizzbee-io/fizzbee/blob/main/examples/references/LANGUAGE_REFERENCE.md#flow-modifiers


Flow modifiers control how statements execute and when they yield control.

## Atomic

Executes all statements indivisibly, without yielding:

```python
atomic action UpdateBoth:
    x = x + 1
    y = y + 1
    # Both updates happen atomically
```

**Use cases**:
- Database transactions
- Critical sections
- Operations that must complete together

## Serial (Default)

Yields between statements, allowing interleaving:

```python
action UpdateBoth:  # serial is default
    x = x + 1  # Yield point after this
    y = y + 1  # Yield point after this
```

**Use cases**:
- Multi-step operations
- Modeling real-world sequencing
- Exploring crash scenarios

## Yield Points

Yield points are where the model checker can schedule other actions or inject faults.

**Yield points occur**:
- After each simple Python statement (in serial context)
- At the end of atomic blocks
- Before and after fizz function calls
- Examples: assignments, `pass`, method calls

**NO yield points after**:
- Control flow keywords: `if`, `elif`, `else`
- Loop keywords: `for`, `while`
- Flow control: `break`, `continue`, `return`
- Guards: `require`
- Non-determinism: `any`, `oneof` (yield after the full statement)
- Inside atomic blocks

**Examples**:

```python
action SerialExample:
    x = 1       # Yield point after
    y = 2       # Yield point after
    if x > 0:   # NO yield point
        z = 3   # Yield point after

atomic action AtomicExample:
    x = 1       # NO yield point (inside atomic)
    y = 2       # NO yield point
    # Yield point here (end of atomic block)

action MixedExample:
    x = 1       # Yield point
    atomic:
        y = 2   # NO yield (inside atomic)
        z = 3   # NO yield
    # Yield point here (end of atomic)
    w = 4       # Yield point
```

**Important for**:
- Crash injection (crashes happen at yield points)
- Action interleaving (other actions can run)
- Understanding execution model

## Parallel

Executes statements concurrently:

```python
atomic action UpdateConcurrently:
    parallel:
        x = x + 1
        y = y + 1
    # Explores all interleavings of the two updates
```

**Use cases**:
- Concurrent operations
- Parallel threads
- Race condition detection

## Oneof

Nondeterministically chooses one branch:

```python
atomic action MakeChoice:
    oneof:
        x = 1
        x = 2
        x = 3
    # Explores all three possibilities
```

**Use cases**:
- Modeling failures (success or failure)
- Non-deterministic choices
- Alternative execution paths

## Nested Modifiers

Flow modifiers can be nested:

```python
action Example:
    serial:
        step1 = True  # Yield after this

        atomic:
            # These execute together
            step2 = True
            step3 = True
```

## Examples

### Atomic Block {#atomic-block}

Atomic blocks execute all statements as one indivisible step No yields or context switches occur within the block

**Demonstrates:** atomic flow modifier on blocks

```fizz
# Example 0006: Atomic Block
# Atomic blocks execute all statements as one indivisible step
# No yields or context switches occur within the block
# Demonstrates: atomic flow modifier on blocks

action Init:
    a = 0
    b = 0

# Without atomic block, each statement could yield
action IncrementSerial:
    # These two statements execute with potential yields between them
    a = a + 1
    b = b + 1

# With atomic block, both statements execute together
action IncrementAtomic:
    atomic:
        # These execute as one indivisible step
        # No other action can observe a != b
        a = a + 1
        b = b + 1

always assertion Consistent:
    # This may fail with IncrementSerial but not with IncrementAtomic
    return a == b
```
Run it in the FizzBee playground: https://fizzbee.io/play


**Expected result** (from `fizz`):

```
StateSpaceOptions: options:{max_actions:100 max_concurrent_actions:2}
Nodes: 2, queued: 0
FAILED: Model checker failed. Invariant: Consistent
------
Init
--
state: {"a":0,"b":0}
------
IncrementSerial
--
state: {"a":1,"b":0}
------
```

[Source on GitHub](https://github.com/fizzbee-io/fizzbee/tree/main/examples/references/02-01-atomic-block)

### Serial Block {#serial-block}

Serial blocks yield after each statement (default behavior) Allows interleaving with other actions between statements

**Demonstrates:** serial flow modifier (explicit form of default)

```fizz
# Example 0007: Serial Block
# Serial blocks yield after each statement (default behavior)
# Allows interleaving with other actions between statements
# Demonstrates: serial flow modifier (explicit form of default)

action Init:
    a = 0
    b = 0

action IncrementSerial:
    require a < 2

    serial:
        # After each statement, the model checker explores:
        # - Continue to next statement
        # - Yield and schedule another action
        # Since a is incremented first, a >= b always holds
        a = a + 1
        b = b + 1

# This assertion holds because serial execution is sequential
# a is always incremented before b in the same action
always assertion OrderPreserved:
    return a >= b

# Add a no-op action to prevent deadlock at terminal state
atomic action NoOp:
    require a >= 2
    pass
```
Run it in the FizzBee playground: https://fizzbee.io/play


**Expected result** (from `fizz`):

```
StateSpaceOptions: options:{max_actions:100 max_concurrent_actions:2}
Nodes: 10, queued: 0
Valid Nodes: 10 Unique states: 9
IsLive: true
PASSED: Model checker completed successfully
```

[Source on GitHub](https://github.com/fizzbee-io/fizzbee/tree/main/examples/references/02-02-serial-block)

### Parallel Block {#parallel-block}

Parallel blocks execute statements concurrently Explores all possible interleavings of the statements

**Demonstrates:** parallel flow modifier for concurrent execution

```fizz
# Example 0008: Parallel Block
# Parallel blocks execute statements concurrently
# Explores all possible interleavings of the statements
# Demonstrates: parallel flow modifier for concurrent execution

action Init:
    a = 0
    b = 0

action ParallelIncrement:
    require a < 2 and b < 2

    parallel:
        # These two statements execute concurrently
        # All interleavings are explored
        # Unlike serial, a can be incremented before or after b
        a = a + 1
        b = b + 1

# This assertion would FAIL with parallel execution!
# Uncommenting it will show that b can be incremented before a
# always assertion OrderPreserved:
#     return a >= b

# With parallel, both a and b can increment in any order
# State space includes paths like: (0,0) -> (1,0) -> (1,1) or (0,0) -> (0,1) -> (1,1)
# In the second path, b > a temporarily!

# Add NoOp to prevent deadlock at terminal states
atomic action NoOp:
    require a >= 2 or b >= 2
    pass
```
Run it in the FizzBee playground: https://fizzbee.io/play


**Expected result** (from `fizz`):

```
StateSpaceOptions: options:{max_actions:100 max_concurrent_actions:2}
Nodes: 69, queued: 0
Valid Nodes: 69 Unique states: 56
IsLive: true
PASSED: Model checker completed successfully
```

[Source on GitHub](https://github.com/fizzbee-io/fizzbee/tree/main/examples/references/02-03-parallel-block)

### Oneof Block {#oneof-block}

Oneof blocks create nondeterministic choice Exactly ONE of the statements is executed per transition

**Demonstrates:** oneof flow modifier for branching state space

```fizz
# Example 0009: Oneof Block
# Oneof blocks create nondeterministic choice
# Exactly ONE of the statements is executed per transition
# Demonstrates: oneof flow modifier for branching state space

action Init:
    choice = "none"

atomic action MakeChoice:
    require choice == "none"

    oneof:
        # The model checker explores paths where exactly ONE of these executes
        # This creates 3 different branches from the initial state
        choice = "A"
        choice = "B"
        choice = "C"

# After MakeChoice runs once, choice will be either "A", "B", or "C"
# Creates 3 branches in the state space from Init

# Add NoOp to prevent deadlock after choice is made
atomic action NoOp:
    require choice != "none"
    pass
```
Run it in the FizzBee playground: https://fizzbee.io/play


**Expected result** (from `fizz`):

```
StateSpaceOptions: options:{max_actions:100 max_concurrent_actions:2}
Nodes: 5, queued: 0
Valid Nodes: 5 Unique states: 4
IsLive: true
PASSED: Model checker completed successfully
```

[Source on GitHub](https://github.com/fizzbee-io/fizzbee/tree/main/examples/references/02-04-oneof-block)

### Failure Trace Through a Parallel Block {#parallel-failure-trace}

Counterexample traces render correctly when an assertion fails inside a parallel block

**Demonstrates:** parallel block, counterexample trace, failure rendering

```fizz
# Example 0089: Failure Trace Through a Parallel Block
# Counterexample traces render correctly when an assertion fails inside a parallel block
# Demonstrates: parallel block, counterexample trace, failure rendering

# When an assertion fails on a state reached mid-parallel, the
# counterexample trace includes threads parked at the parallel join
# (frames with no program counter). The failure-path renderer must
# handle those frames. (Regression: this used to panic in
# CurrentPcSourceInfo instead of printing the trace.)

action Init:
    a = 0
    b = 0

action NoOp:
    pass

always assertion NoOverflow:
    return a < 2

parallel action Both:
    a = a + 1
    b = (b + 1) % 3
```
Run it in the FizzBee playground: https://fizzbee.io/play


**Expected result** (from `fizz`):

```
StateSpaceOptions: options:{max_actions:100 max_concurrent_actions:2}
FAILED: Model checker failed. Invariant: NoOverflow
------
Init
--
state: {"a":0,"b":0}
------
Both
--
state: {"a":0,"b":0}
------
Stmt:0
--
state: {"a":1,"b":0}
------
Both
--
state: {"a":1,"b":0}
------
Stmt:0
--
state: {"a":2,"b":0}
------
```

[Source on GitHub](https://github.com/fizzbee-io/fizzbee/tree/main/examples/references/02-05-parallel-failure-trace)

### Nested Flow Modifiers {#nested-flow-modifiers}

Flow modifiers can be nested with different behaviors

**Demonstrates:** nested atomic within serial, serial within atomic

```fizz
# Example 0053: Nested Flow Modifiers
# Flow modifiers can be nested with different behaviors
# Demonstrates: nested atomic within serial, serial within atomic

action Init:
    counter = 0
    value = 0

action SerialWithAtomic:
    require counter < 2

    # Serial action (default) with atomic block
    counter = counter + 1  # Can yield here

    # Atomic inner block (no yielding within)
    atomic:
        value = value + 1
        value = value + 10

atomic action AtomicWithSerial:
    require counter < 2

    # Whole action is atomic despite inner serial
    x = counter

    # Serial inner still allows yields
    serial:
        value = value + x
        value = value + 1

atomic action NoOp:
    if counter >= 2:
        pass
```
Run it in the FizzBee playground: https://fizzbee.io/play


**Expected result** (from `fizz`):

```
StateSpaceOptions: options:{max_actions:100 max_concurrent_actions:2}
Nodes: 5206, queued: 0
Skipping dotfile generation. Too many Nodes: 5206
Valid Nodes: 5206 Unique states: 5200
IsLive: true
PASSED: Model checker completed successfully
```

[Source on GitHub](https://github.com/fizzbee-io/fizzbee/tree/main/examples/references/12-01-nested-flow-modifiers)


## Patterns that use this

- [Mutex Pattern](/design/patterns/mutex/)
- [Read-Write Lock Pattern](/design/patterns/read-write-lock/)
- [Distributed Lock Pattern](/design/patterns/distributed-lock/)
- [Optimistic Locking Pattern](/design/patterns/optimistic-locking/)
- [Saga Pattern](/design/patterns/saga-pattern/)
- [Snapshot Isolation Pattern](/design/patterns/snapshot-isolation/)
- [Compare-And-Swap Pattern](/design/patterns/compare-and-swap/)
- [Producer-Consumer Pattern](/design/patterns/producer-consumer/)
- [Message Queue Pattern](/design/patterns/message-queue/)
- [Cache Coherence Pattern](/design/patterns/cache-coherence/)
- [Eventual Consistency Pattern](/design/patterns/eventual-consistency/)
- [Idempotent Operations Pattern](/design/patterns/idempotent-operations/)
- [Circuit Breaker Pattern](/design/patterns/circuit-breaker/)
- [Rate Limiting Pattern](/design/patterns/rate-limiting/)
- [Write-Ahead Log Pattern](/design/patterns/write-ahead-log/)
- [Event Sourcing Pattern](/design/patterns/event-sourcing/)

