Pointer slicing

Indexing a pointer with a range turns raw memory into a slice: a view with a length, whose indexing and iteration are checked from then on. Because a pointer has no length of its own, the range must say where the view ends.

ExpressionElements, counting from pLength
p[..n]0 up to, not including, nn
p[..=n]0 to n inclusiven + 1
p[a..b]a up to, not including, bb - a
p[a..=b]a to b inclusiveb - a + 1

The view's type follows the pointer's writability: a *var T gives a var T[..], and a *T gives a T[..]. A view of a null pointer with a length of zero is an empty view.

import Memory::{ Alloc, Free };

func Fill(values: var int[..], start: int) {
    for i in 0..values.length {
        values[i] = start + i as int;
    }
}

func Total(values: int[..]) -> int {
    var sum = 0;
    for value in values {
        sum += value;
    }
    return sum;
}

func Main() -> int {
    let count: uint = 4;
    let block = Alloc(count * sizeof(int)) as *var int;
    if block == null {
        return 1;
    }
    defer Free(block);

    let all = block[..count];      // var int[..], four elements
    Fill(all, 10);                 // 10, 11, 12, 13
    let total = Total(block[1..3]);    // 11 + 12
    return 0;
}

The end is required

A pointer does not know how far its memory extends, so a range with no end — p[..] or p[a..] — is rejected:

error: cannot slice pointer '*var int' without an end bound
  help: write 'p[..n]' or 'p[a..b]' to give the slice a length

Once built, the view checks every index against the length it was given. That length is the program's promise, and nothing checks it against the memory: block[..100] over a four-element block compiles, and its indexes are then checked against 100, not 4. Build every view from the count the memory was allocated with.

Precedence

@ is a prefix operator and indexing is postfix, so postfix binds first: @a[0][..2] means @(a[0][..2]) — a slice of the element a[0], which is not a sequence:

error: cannot slice value of type 'int'
  help: declare 'func []' taking a range on 'int'

Parenthesise the address to slice the memory it points at:

var numbers: int[6] = [1, 2, 3, 4, 5, 6];
let window = (@numbers[2])[..3];   // var int[..]: 3, 4, 5

A view of an array is more simply numbers[2..5]; slicing a pointer is for memory that arrives as an address, such as an allocation, a buffer from a foreign function, or a flexible tail.

Views of literal text

The .data of a string literal is a *char8, and slicing it gives back a read-only view, as any read-only pointer does: "abc".data[..2] is a char8[..] of a and b.

See also