Skip to content

Ranges and Spread

The .. and ..= ranges generate sequences of integers. The exclusive form start..end goes up to end - 1; the inclusive form start..=end includes the last value. Ranges can be used in for, stored in variables, and used to slice arrays and strings.

Exclusive and inclusive ranges in for, storing a range in a variable, and array slicing.

09-ranges.zolo
Playground
// Feature: Range operators `..` (exclusive) and `..=` (inclusive)

// Syntax: `start..end` (up to end-1) and `start..=end` (up to end)

// When to use: generate sequences for `for`, slice arrays/strings.

// Same semantics as Rust and Python (but Python only has `..` via

// `range`).


// Exclusive range — does not include the end.

for i in 0..5 {
  print(i)
}

// expected: 0, 1, 2, 3, 4


print("---")

// Inclusive range — includes the end.

for i in 0..=3 {
  print(i)
}

// expected: 0, 1, 2, 3


print("---")

// Range can be stored in a variable.

let r = 1..=5
var total = 0
for i in r { total = total + i }
print(total)  // 15


// Slicing an array with a range.

let arr = [10, 20, 30, 40, 50]
print(arr[1..3])  // [20, 30] (indices 1 and 2)

print(arr[2..=4])  // [30, 40, 50]


// Counting down: use stdlib (not native). Workaround:

var down = []
for i in 0..5 {
  let v = 4 - i
  down = [...down, v]
}
print(down)  // [4, 3, 2, 1, 0]


// Range size.

var count = 0
for _ in 0..100 { count = count + 1 }
print(count)  // 100

The spread operator ... expands an array inside an array literal. It is the idiomatic way to concatenate arrays or insert elements in the middle of a sequence. Also use it in function parameters as ...T for variadic functions.

Concatenation with [...a, ...b], shallow copy, and variadic ...int parameter.

10-spread.zolo
Playground
// Feature: Spread `...` in array literals

// Syntax: `[...a, ...b]` in array literal (concatenates)

// When to use: copy and/or concatenate arrays without calling

// functions. Important restrictions:

//   - Only works in array literals.

//   - Does NOT work in destructuring (`let (h, ...t) = ...`).

//   - Does NOT work in calls (`f(...arr)` is an error).

//   - For varargs in functions, use `...` on the parameter TYPE.


// Concatenate two arrays.

let a = [1, 2, 3]
let b = [4, 5]
let c = [...a, ...b]
print(c)  // [1, 2, 3, 4, 5]


// Insert elements between spreads.

let d = [0, ...a, 99, ...b, 100]
print(d)  // [0, 1, 2, 3, 99, 4, 5, 100]


// Shallow copy — `[...arr]` creates a new array.

let original = [10, 20, 30]
var copy = [...original]
copy.push(40)
print(original)  // [10, 20, 30] (intact)

print(copy)  // [10, 20, 30, 40]


// Spread applies to any array-shaped expression.

fn make_seq(n: int) -> [int] {
  var result = []
  for i in 0..n { result = [...result, i] }
  return result
}

let combined = [-1, ...make_seq(3), -2]
print(combined)  // [-1, 0, 1, 2, -2]


// Varargs (related topic): `...` goes ON THE TYPE of the parameter.

fn sum_all(nums: ...int) -> int {
  var total = 0
  for n in nums { total = total + n }
  return total
}

print(sum_all(1, 2, 3, 4, 5))  // 15

print(sum_all())  // 0

Challenge

Create two arrays and join them with spread, inserting the number 0 exactly in the middle. Verify that the original arrays were not modified.

See also

enespt-br