Skip to content

Loops

Use Atoll's four for-loop forms for iteration, conditions, pattern consumption, and infinite loops.

Updated View as Markdown

Atoll uses for for every kind of loop. The tokens between for and the body select one of four forms.

Form Shape Continues while
Iteration for pattern in value { ... } The iterable yields another value
Condition for condition { ... } The condition is true
Pattern consume for pattern := expression { ... } The expression matches the pattern
Infinite for { ... } A control-flow expression exits the loop

There is no separate while or loop keyword.

Iterate over values

for pattern in value evaluates the iterable and binds each yielded value to the pattern.

fn sum(values: []int): int {
    mut total := 0
    for value in values {
        total += value
    }
    return total
}

Ranges are iterable:

for index in 0..10 {
    process(index)
}

The binding position accepts patterns. Parentheses are optional for the top-level tuple shorthand.

for key, value in entries {
    store(key, value)
}

An underscore ignores a yielded value:

for _ in 0..3 {
    retry()
}

Loop on a condition

for condition checks a bool before each iteration.

mut remaining := 3
for remaining > 0 {
    tick(remaining)
    remaining -= 1
}

If the first check is false, the body does not run.

Consume matching values

for pattern := expression evaluates the expression before every iteration. If the result matches, the pattern’s bindings are available in the body. If it does not match, the loop ends.

for Some(message) := inbox.next() {
    handle(message)
}

Conceptually, this is repeated pattern matching with the non-matching case exiting the loop. It is useful for consuming Option values, iterator protocols, queues, and other stateful sources.

Loop indefinitely

A subjectless for repeats until its body transfers control elsewhere.

for {
    message := receive()
    if message.is_shutdown() {
        break
    }
    handle(message)
}

Break with a value

Loops are expressions. break value supplies the loop’s result.

answer := for {
    candidate := next_candidate()
    if candidate.is_valid() {
        break candidate
    }
}

All reachable value-bearing exits must agree on a result type. A loop without a value-bearing break is normally used for control flow rather than assigned.

Continue

continue skips the rest of the body and starts the next iteration.

for value in values {
    if value < 0 {
        continue
    }
    consume(value)
}

For a condition or pattern-consume loop, the head is evaluated again. For an iteration loop, the iterable is advanced.

Labels

Prefix a loop with 'name: and pass the label to break or continue when nested loops make the target ambiguous.

'outer: for row in rows {
    for cell in row {
        if cell.is_terminal() {
            break 'outer
        }
    }
}

A labeled break may also carry a value:

found := 'search: for group in groups {
    for item in group {
        if matches(item) {
            break 'search item
        }
    }
}

How the parser distinguishes forms

After for, an immediate { selects the infinite form. Otherwise, a top-level := selects pattern consumption, a top-level in selects iteration, and the remaining shape is a boolean condition. Delimiters inside the head do not affect that decision.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close