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

Suites, conditionals, and returns

A suite’s final expression supplies its value. Other expressions evaluate and are discarded, except that implicitly discarding a Result is a compile error. Handle it with ?, matching, or a function; drop(result) explicitly discards it. This applies in non-final conditionals, matches, loops, resource scopes, and generator bodies. It does not prohibit unused bindings, Option, or aggregates containing Results.

Continuing branches of value-producing if/elif/else suites must agree on type. An if without else can only produce unit. The inline conditional uses value_if_true if condition else value_if_false; only its selected value is evaluated.

An if takes any number of elif arms. The arms are alternatives at one level, tested in order; they do not count toward the nesting limit. An if written inside an else suite does.

def clamp_low(value: i64, minimum: i64) -> i64:
    if value < minimum:
        return minimum
    value

return value exits the enclosing function from any suite. Bare return returns unit. return if condition: returns its selected suite’s value. return match value: returns the final expression of the selected case. Every explicit return must match the declared result, including returns in non-final or statically unchosen branches.

A returning branch contributes no value to paths that continue. Every continuing function path must still produce the declared result; an if without else cannot prove that all paths return. This analysis follows structure without constant-condition folding. Statements after an explicit return or an exhaustive conditional whose branches all return are unreachable errors.

break and continue likewise contribute no branch value when they exit a suite inside a loop. Ordinary exits perform cleanup.

An if as a statement’s value

A block if can be the whole right-hand side of a binding or single-place assignment, or follow return. Its selected suite’s final expression supplies the value:

def classify(flag: bool) -> Result[i64, OverflowError[i64]]:
    result = if flag:
        base = 10
        base + 1
    else:
        2
    Ok(result * 2)

def main() -> Result[(), IoError | OverflowError[i64]]:
    print(classify(True)?, classify(False)?)?
    Ok(())
22 4

mut and annotations work as for ordinary bindings. An annotation or the assigned destination’s type supplies the expected type to every continuing arm, including every elif and else; this allows contextual Nothing and empty collection literals. Continuing arms must agree. Arms ending in return, break, or continue contribute no value. If every arm exits, write an ordinary if statement instead of binding its nonexistent value. An absent else produces unit on its unselected path; unit cannot be stored in a binding.

Conditions are evaluated in order; only the selected suite runs. Its locals are cleaned up before the binding or assignment, including before evaluating destination indices. ?, return, break, and continue keep their enclosing function or loop. A binding or assignment cannot receive a reference or a closure with borrowed captures from the block; produce an owned value instead. These are the same lifetime and evaluation rules as a match used as a value.

return if condition: returns each selected suite’s final expression as though it ended with return expression. Returned references follow ordinary returned-reference rules, and calls in these final positions remain source-tail calls. A suite without a value returns unit. Every path leaves the enclosing suite, so a statement directly after the whole block is unreachable. An arm that executes break or continue still exits to its enclosing loop rather than returning from the function; code after that loop can run.

The block ends the statement. Block if and match remain unsupported inside call arguments, operands, augmented assignments, or assignments to several targets. Bind the selected value first, or use an inline conditional for two single expressions.