Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Conditionals

Grammar

conditional_decl   = "conditional" expression "{" { conditional_branch } "}".
conditional_branch = (literal_pattern | "_") "=>" "{" { relationship_decl | relationship_use } "}".
literal_pattern    = [ "-" ] literal.

A conditional evaluates its match subject, the expression after the keyword, and activates the branch, if any, whose literal equals the result. Only that branch’s relationships participate in resolution. Branch bodies accept relationship declarations and component uses, but no cell declarations or nested conditionals. Branches have no comma separator or terminator.

The match subject

The match subject may be a cell name (conditional mode { ... }) or an expression with deduced dependencies:

sheet resample_demo {
    source resample: bool = true;
    source constrain: bool = true;
    cell locked: bool = false;

    conditional resample && constrain {
        true => {
            relationship {
                locked := true;
            }
        }
        false => {
            relationship {
                locked := false;
            }
        }
    }
}

Every branch literal’s type must match the match subject’s own inferred type exactly; a sheet mixing an i32 match subject with a bool branch literal fails to parse, not to propagate. The match subject can also be tuple-valued, but tuple expressions are not literal patterns, so such a conditional can use only the _ default branch.

Forced cells

A relationship with exactly one method claims its output whenever active, regardless of strength. The output is forced, as reported by Sheet::is_forced. This query returns false for a relationship with multiple methods, even when strength selects the same direction every round.

Host UIs commonly disable editing for forced cells because resolution overrides their writes. The language does not require this convention; a host may accept a write and preserve it as shadow state.

Shadow state: forced and self-referencing cells

A forced cell preserves its source underneath its derived value, as filters and self-referencing methods do.

sheet range_bounds {
    source mode: i32 = 0;
    cell low: i32 = 4;
    cell high: i32 = 9;

    conditional mode {
        0i32 => {
            relationship {
                low := min(low, high);
                high := max(low, high);
            }
        }
        1i32 => {
            relationship {
                low := high;
            }
        }
    }
}

With mode == 0 (the declared default), the self-referencing branch is active. Strength selects one of its two methods, low := min(low, high) or high := max(low, high). low, declared first, is stalest, so the solver picks low := min(low, high); high is left alone as an ordinary source, its own max method never invoked. low and high start at 4 and 9, already satisfying low <= high, so nothing visibly changes.

Writing high to 42 and switching to mode == 1 activates the single-method branch, forcing low from high: low reads 42, but its source is still 4. Writing high did not change low‘s source. Switching back to mode == 0 reselects low := min(low, high) (still the stalest cell) and recomputes it from both cells’ sources, 4 and 42, rather than the forced 42: low reads back down to 4; high, never written since the first round, is still the one left as a source, at 42.

Writing low to 100 promotes it to freshest, flipping the solver’s choice: now high := max(low, high) is the one selected, deriving high and leaving low as the source instead. high reads 100, pulled up to match.

The default branch and reverting to source

_ => { ... } matches any value not listed by a named branch and must appear last. A named branch after _ is a syntax error. The default branch is optional: if the match value doesn’t equal any branch’s literal, none of the conditional’s relationships are active that round, and their outputs become freely writable. Forced and self-referencing cells preserve a separate source value, so releasing those cells restores their last external write or declared default. Ordinary cells in reversible relationships need not retain a separate shadow; releasing the relationship does not promise to undo their last derived value. The previous section demonstrates the shadow-state mechanism for forced and self-referencing cells.

sheet no_default {
    source mode: i32 = 0;
    cell x: f64 = 1.0;

    conditional mode {
        0i32 => {
            relationship {
                x := 100.0;
            }
        }
    }
}

Nested and chained conditionals

Sibling conditionals may read one another’s outputs as match subjects or relationship inputs. Branch bodies cannot contain conditionals. A resize dialog might use two sibling conditionals, one gated on resample, the other on resample && constrain.