Skip to content

Indexing and loops

Arbor uses zero-based indexing, explicit range boundaries, and structured loops. Loop else has a precise empty-iteration meaning.

Design documentation

This chapter describes the language design. Examples are illustrative; implementation availability and unresolved rules are explained in Design status.

Boundary examples

For a list with five elements, values[0] addresses the first element and values[4] the last. values[-1] and values[5] are invalid. The slice values[2..<5] contains the final three elements; an end bound beyond the collection is invalid rather than silently clipped.

A for loop that receives even one element skips its else, including when that element immediately triggers break or continue.

Indices and ranges

Indexing is zero-based. Negative indices are invalid. Out-of-bounds access raises a declared exception; explicit last-element operations cover end-relative use.

Ranges distinguish exclusive and inclusive ends:

0..<5              // 0, 1, 2, 3, 4
1..=5              // 1, 2, 3, 4, 5
values[2..<5]      // Elements 2, 3, 4

Slices are half-open. Equal valid bounds produce an empty slice. Invalid bounds raise rather than silently clipping. Range steps, reversed ranges, open-ended slices, and exact result ownership remain open.

Loop forms

for value in values {
    process(value)
}

for (index, value) in values.enumerate() {
    ...
}

while connection.is_open {
    process_next()
}

loop {
    if finished {
        break
    }
    process_next()
}

while is retained; loop expresses unconditional repetition. C-style three-part for is omitted from the v0.1 direction. Infinite iterators remain useful when they supply values. Ordinary iteration lends read-only elements; explicit mutable iteration lends exclusive mutable access. Structural mutation is disallowed while the relevant iteration borrows are active.

Break depth

break means break 1. break N exits exactly N lexically enclosing loops. N is a positive integer literal, and excess depth is a compilation error. It never denotes a returned value. Cleanup runs for each exited ordinary scope.

loop {
    for item in items {
        if finished(item) {
            break 2
        }
    }
}

continue is supported. Depth-qualified continue has not been selected.

Empty-iteration else

for user in users {
    display(user)
} else {
    display("No users")
}

This has Jinja-style meaning: else runs only if iteration produces zero elements. It does not mean Python's completion-without-break rule.

  • One element followed by break does not trigger else.
  • Immediately continuing still counts as having received an element.
  • Iterator acquisition/advancement failures propagate and do not trigger else.
  • The else block is outside that loop when calculating break depth.
  • The rule applies to async iteration too.
  • Else is not added to while or loop.