Language Policy

Patterns & Control Flow

Canonical grammar, semantics, constraints, and deferred boundaries for Patterns & Control Flow.

Control flow is expression-oriented, and patterns define exactly how one evaluated value is tested, narrowed, destructured, bound, and checked for coverage.

Policy

if and match produce values when their branches agree. match arms always begin with case; _ is the catch-all. Patterns include literals, ranges, bindings, type tests, constructors, arrays with .. rest, structural records, nominal records, and ordered or-patterns. if let evaluates once and exposes immutable bindings only in its success body; while let repeats that test and exits on the first mismatch.

Specified behavior

A guarded match arm contributes no exhaustiveness coverage. Closed enums are checked by variant and irrefutable payload coverage. List rest receives an Array<T>. Nominal record patterns test declaration identity before fields and evaluate subpatterns left to right. Or-pattern alternatives test left to right with scratch bindings; accepted binding alternatives must expose the same names with one connected overlap type. Expression for collects body tails in source order, while statement for and while are valueless.

Constraints and loud decline

...rest, qualified enum cases, empty nominal-record patterns, parenthesized patterns, while let ... else, guards in an if let head, and escaping pattern bindings are rejected. A refutable comprehension pattern mismatch is a fault, not an implicit filter. Bare break and continue need a local loop target; only contextual loop declares labels and joins break values. Top-level return and general statement-valued match arms are static errors.

Deferred boundary

Goto-like labels, labels on while or for, cross-function control transfer, public Never, stronger termination claims, broader pattern heads, and fault-catching control forms are deferred. Where the scrutinee is not statically finite enough, canonical examples provide an explicit catch-all.

Worked example

TOPAZ
function describe(values: Array<int>) -> string {
    match values {
        case [] => "empty"
        case [only] => "one: {only}"
        case [head, ..tail] => "head: {head}, rest: {tail.length}"
    }
}

let label = describe([1, 2, 3])