Sequences · Lesson 5.2

Array repeat

Source
Build an array of many equal elements with [0; 16], and see that the repeated value is evaluated only once.
You'll need: Array, Function

Listing every element works for four values, not for sixteen — and not at all for a thousand. [value; count] builds an array of count copies of one value: [0; 16] is sixteen zeros. This lesson shows the form, its one surprise, and the job it is usually given: starting an array from a clean slate.

Many copies of one value

let zeros: int32[16] = [0; 16];

Read [0; 16] as "zero, sixteen times". The element type comes from the variable — here int32, because the variable says int32[16] — and the count must match the count in the type.

The count must be known at compile time, because it becomes part of the array's type. A literal works, and so does a const, but a let variable does not: its value is only known once the program runs.

The value is evaluated once

The surprise is in how the value is produced. It is evaluated exactly once, and that one result is copied into every element:

let rolls = [Roll(); 4];

Roll prints a line every time it is called, and the output shows Roll called only once. The four elements are always equal, whatever Roll returns.

flowchart LR
    r["Roll()<br/>called once"] --> v["4"]
    v --> e0["rolls[0] = 4"]
    v --> e1["rolls[1] = 4"]
    v --> e2["rolls[2] = 4"]
    v --> e3["rolls[3] = 4"]

If you want each element computed on its own, list them — [Roll(), Roll(), Roll(), Roll()] makes four calls — or fill the array in a loop.

A clean slate to fill in

The usual reason to repeat a value is to start a var array from zero and fill it in afterwards. Here, a tally of the last digit of each number:

var tally: int32[10] = [0; 10];
let numbers: int32[8] = [12, 7, 22, 35, 2, 17, 40, 32];
for number in numbers {
    tally[number % 10] += 1;
}

number % 10 is the last digit, 0 to 9, so it is always a valid index into tally. Each element counts how many numbers end in that digit: 12, 22, 2 and 32 all land in tally[2].

The program

The whole lesson is one package in the Examples repository. Its comments explain every step.

Src/Main.rux
// Listing every element works for four values, not for sixteen. `[value; count]` builds an array
// of `count` copies of one value: `[0; 16]` is sixteen zeros, of type `int32[16]` when the
// variable says so.
//
// The surprise is in how the value is produced. It is evaluated exactly once, and that one
// result is copied into every element. `[Roll(); 4]` calls `Roll` once, not four times, so the
// four elements are always equal.
import Io::PrintLine;

// Prints a line every time it is called, so the output shows how many calls happened.
func Roll() -> int32 {
    PrintLine("Roll called");
    return 4;
}

func Main() -> int {
    // The count must be known at compile time; the element type comes from the variable.
    let zeros: int32[16] = [0; 16];
    PrintLine("zeros: length {}, first {}, last {}", zeros.length, zeros[0], zeros[15]);

    // One call, four copies of its result.
    let rolls = [Roll(); 4];
    PrintLine("rolls: {} {} {} {}", rolls[0], rolls[1], rolls[2], rolls[3]);

    // The usual reason to repeat a value is to start a `var` array from a clean slate and
    // fill it in afterwards. Here, a tally of the last digit of each number.
    var tally: int32[10] = [0; 10];
    let numbers: int32[8] = [12, 7, 22, 35, 2, 17, 40, 32];
    for number in numbers {
        tally[number % 10] += 1;
    }
    for digit in 0..tally.length {
        if tally[digit] > 0 {
            PrintLine("ending in {}: {}", digit, tally[digit]);
        }
    }
    return 0;
}

Run it

cd Examples/Sequences/ArrayRepeat
rux run
zeros: length 16, first 0, last 0
Roll called
rolls: 4 4 4 4
ending in 0: 1
ending in 2: 4
ending in 5: 1
ending in 7: 2

Common mistakes

A count only known at run time.
With let n = 4;, the literal [0; n] fails with error: array repeat count must be a non-negative compile-time integer. Use a literal or a const.
A count that disagrees with the type.
let b: int32[5] = [0; 4]; fails with error: cannot assign 'int[4]' to 'int32[5]'. The repeat count and the type's count have to be the same number.
Expecting a fresh value per element.
[Roll(); 4] calls Roll once. If each element should be different, list the calls or assign the elements in a loop.

Try it yourself

  1. Declare const Size = 5; and use it in both places: var squares: int32[Size] = [0; Size];. Fill the array with the squares of its indices — they are uint, so convert with as int32.
  2. Replace [Roll(); 4] with [Roll(), Roll(), Roll(), Roll()] and count the Roll called lines.
  3. Change the tally to count the remainders of each number divided by 3 instead.
  4. Try [0; n] with a let n = 4; and read the error.

Learn more

  • Arrays in the Rux Reference
  • Const — a value known at compile time
  • Array nested — repeating a whole row to build a grid