Loops
while repeats as long as the condition is true:
05-while.zolo
// Feature: `while` — loop while a condition is true
// Syntax: `while cond { ... }`
// When to use: iteration with a dynamic criterion that isn't
// a fixed range (e.g. read until a sentinel, drain a queue,
// retry with backoff).
var i = 1
var sum = 0
while i <= 5 {
sum = sum + i
i = i + 1
}
print("sum 1..5 = {sum}") // sum 1..5 = 15
// `while` with mutation of two variables of state.
var a = 0
var b = 1
while a < 50 {
print(a)
let next = a + b
a = b
b = next
}
// expected (Fibonacci below 50): 0 1 1 2 3 5 8 13 21 34
while-let repeats as long as a pattern matches — perfect for consuming
until exhausted:
06-while-let.zolo
// Feature: `while let` — loop while a pattern matches
// Syntax: `while let Pattern = expr { ... }`
// When to use: consume generators / iterators / queues
// that return Option/enum until the "end" (None / nil).
// A classic generator that produces numbers down to zero.
fn* countdown(n: int) {
let mut i = n
while i > 0 {
yield i
i = i - 1
}
}
let gen = countdown(3)
// `while let` consumes from gen until it's exhausted.
// `gen()` returns nil at the end — direct comparison with nil.
let mut val = gen()
while val != nil {
print("tick {val}")
val = gen()
}
// expected:
// tick 3
// tick 2
// tick 1
// `while let` is the shortcut for the "loop until nil" pattern.
// Equivalent without the shortcut would be:
//
// let mut v = gen()
// loop {
// if v == nil { break }
// print("tick {v}")
// v = gen()
// }
loop is the explicit infinite loop; break can return a value:
break <value> turns the loop into an expression.
07-loop-infinite.zolo
// Feature: infinite `loop` + `break` with a value
// Syntax: `loop { ... break expr }`
// When to use: an event-driven loop where the exit condition
// is only known mid-body. Allows returning a value via `break`
// (turning the loop into an expression).
// Basic form — break without a value.
var count = 0
loop {
count = count + 1
if count >= 5 {
break
}
}
print("counted to {count}") // counted to 5
// `loop` as an expression: `break value` makes the loop yield `value`.
// SKIP: `break <expr>` (loop-as-expression yielding a value) is not
// yet supported in the runtime — the assignment side keeps the
// pre-break value, so we mutate a captured variable instead.
var n = 0
loop {
n = n + 1
if n * n > 100 {
break
}
}
let found = n
print("first n with n^2>100: {found}") // 11
for iterates over ranges and collections:
Exclusive range 0..n (does not include n).
08-for-range-exclusive.zolo
// Feature: `for i in 0..10` — exclusive range
// Syntax: `for var in start..end { ... }`
// When to use: iterate indices of a known size — goes
// from `start` to `end - 1`. The standard pattern for "0 to length".
print("0..5:")
for i in 0..5 {
print(" {i}") // 0, 1, 2, 3, 4
}
// Range with boundary variables.
let n = 3
print("0..{n}:")
for i in 0..n {
print(" {i}") // 0, 1, 2
}
// Empty range: start == end -> never runs.
print("3..3 (empty):")
for i in 3..3 {
print(" never appears {i}")
}
print("end")
// expected:
// 3..3 (empty):
// end
Inclusive range 0..=n (includes n).
09-for-range-inclusive.zolo
// Feature: `for i in 0..=10` — inclusive range
// Syntax: `for var in start..=end { ... }`
// When to use: when the upper bound is conceptually
// "the last valid position" and must participate — e.g.
// days of the month `1..=31`, scores `0..=100`.
print("1..=5:")
for i in 1..=5 {
print(" {i}") // 1, 2, 3, 4, 5
}
// Practical difference vs exclusive.
var sum_excl = 0
for i in 1..10 { sum_excl = sum_excl + i }
print("1..10 = {sum_excl}") // 45
var sum_incl = 0
for i in 1..=10 { sum_incl = sum_incl + i }
print("1..=10 = {sum_incl}") // 55
Iterating over the elements of an array.
10-for-array.zolo
// Feature: `for x in array` — collection iteration
// Syntax: `for elem in iterable { ... }`
// When to use: walk arrays/lists without caring about
// the index. More readable than `for i in 0..arr.len()`.
let fruits = ["apple", "banana", "cherry"]
for f in fruits {
print("fruit: {f}")
}
// Iteration with sum.
let nums = [10, 20, 30, 40, 50]
var total = 0
for n in nums {
total = total + n
}
print("total = {total}") // total = 150
// Combines well with structs/enums.
enum Shape {
Circle(float),
Rectangle(float, float),
}
let shapes = [Shape.Circle(2.0), Shape.Rectangle(3.0, 4.0)]
for s in shapes {
let descr = match s {
Shape::Circle(r) => "circle r={r}",
Shape::Rectangle(w, h) => "rectangle {w}x{h}",
}
print(descr)
}
break and continue control the iteration:
20-break-continue.zolo
// Feature: `break` and `continue` in loops
// Syntax: `break` (exit the loop), `continue` (skip to the
// next iteration)
// When to use: `break` to stop before the natural end;
// `continue` to skip cases without nesting `if`.
// `continue` — skip even numbers.
print("odd numbers in 0..10:")
for i in 0..10 {
if i % 2 == 0 {
continue
}
print(" {i}")
}
// expected: 1, 3, 5, 7, 9
// `break` — exit early when you find what you want.
let nums = [3, 8, 12, 5, 7, 20, 1]
var found = -1
for n in nums {
if n > 10 {
found = n
break
}
}
print("first > 10: {found}") // 12
// Nested loops — break only exits the innermost.
print("partial multiplication table:")
for i in 1..=4 {
for j in 1..=4 {
if i * j > 8 {
break // only exits the inner for j
}
print(" {i} x {j} = {i * j}")
}
}
// `continue` in while.
var i = 0
while i < 10 {
i = i + 1
if i % 3 == 0 {
continue // skip multiples of 3
}
print(" i={i}")
}
// expected: 1, 2, 4, 5, 7, 8, 10
Challenge
Rewrite the exclusive for 0..5 as a while with a manual counter and run
both — the output should be identical.
See also