Skip to content

Loops

while repeats as long as the condition is true:

05-while.zolo
Playground
// 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
Playground
// 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
Playground
// 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
Playground
// 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
Playground
// 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
Playground
// 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
Playground
// 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

enespt-br