A slice copies. A span reads someone else’s elements in place: a value of three words — a data pointer and two bounds — that walks storage it does not own. It is the same view a conformant parameter has always carried; span of T is that view’s positional spelling, and 7.0.0 lets it stand in var, parameter and return positions.

The example is examples/Spans. Build and run it:

make -C examples/Spans run

Borrowing a sub-range

var
    xs : span of int64;

xs := Span(series, 2, 5);
WriteLn("  Sum(Span(series, 2, 5)) = %lld", Sum(xs));

Three words move, zero elements do — and the borrowed window admits anywhere the conformant view admits, including every math verb. The proof it is a view and not a copy is one edit:

series[3] := 100;
WriteLn("  after series[3] := 100 the same span sums to %lld", Sum(xs));

The span sees the new value, because there is no copy to go stale.

The view verbs and the lending law

RowView answers a matrix row as a span; WindowView answers count elements of a vector from start. Both copy nothing — and both spell the lending law in their signatures:

row := RowView(address m, 1);
Sum(WindowView(address v, 2, 3));

A view that escapes a call must come from storage the caller visibly lent. So a view producer takes its source through a pointer — address m, the same visible-mutation marker every write path in Mica wears — and the caller keeps m alive while the span is read. Forget the address and the inference diagnostic teaches the spelling back (5446, naming 'address m').

The payoff is the allocation-free per-axis reduction:

Sum(RowView(address m, 2)) / 4.0     { row 2's mean: one line, zero copies }

What a span refuses

The borrow stays scope-shaped, and every escape is refused at compile time, by name:

The program tried toThe answer
a span in a record field or array elementa span cannot stand in <position>: a span is a borrowed view whose backing may die before the position it would rest in
a span as a task parameterthe same durable-position refusal — a task’s frame outlives its scheduling site
return a span rooted in a localthe return-root rule: a returned span roots in the frame’s own parameters
write through a spanspan of T is the read face by law; writing keeps the explicit pointer array[lo..hi : int64] of T binder spelling
grow a dynamic array while a named window borrows itrefused (5488) — growth moves the backing, so the window is admitted and the growth is not

Empty is honest

WindowView(address v, 0, 0) answers the empty span: walks run zero times, Sum answers zero, and the champions fail as absence — no sentinel values anywhere.

What this does not do

  • No writable span. One face, the read face. The writable view keeps its pointer-spelled binder, so every write path still says address.
  • No span of spans, no span fields. The depth rule follows one borrow, and positions it cannot follow are refused rather than documented.
  • No lifetime annotations. The lending law is structural — the address at the call site is the annotation, and the reader sees it.

Try it

Delete the address from RowView(address m, 1) and read the diagnostic — it names the lending spelling. Then try storing xs into a record field and meet the durable-position refusal.

Next

Spans are how the reduction verbs serve every one-dimensional shape with one signature — and the runtime-length layer the whole math unit is built on.