Summary#
Enumerable.Range(start, count) is a sequence of count consecutive integers beginning at start. It is what you
foreach over when the thing you are iterating is an index rather than a row — and it is the only way to do that
inside a render block, which has foreach and no for.
Signature#
Enumerable.Range(<start>, <count>) // → int[] — count integers, starting at startDescription#
The second argument is a COUNT, not an end#
Enumerable.Range(0, 4) is 0, 1, 2, 3 — four values. This is C#'s signature exactly, and the mistake worth naming
once: it is not Range(first, last).
countof0is an empty sequence, and iterating it renders nothing. That is the case a count computed from data hits first, so it is well-defined rather than an error.- A negative
count, or a range whose last value would passint.MaxValue, fails loudly.
A fixed grid in a render block#
A render block iterates with foreach; there is no for. So anything laid out by position — a board, a calendar
month, a star rating, a fixed number of skeleton placeholders — is a foreach over a range:
[Page("/board")]
[AllowAnonymous]
component Board() {
render {
Stack(gap: 0) {
foreach (var row in Enumerable.Range(0, 8)) {
Row(gap: 0) {
foreach (var col in Enumerable.Range(0, 8)) {
Box(w: "40px", h: "40px", bg: (row + col) % 2 == 0 ? "#eee" : "#333");
}
}
}
}
}
}The inner range is evaluated per outer element, exactly as a nested loop reads.
A range or a for loop, in a function body?#
It works in a function too, and there it is a matter of taste against for: reach for for when you
need the index to drive something (a mutable step, an early exit), and for a range when you are iterating a fixed
number of values.
int SumTo(int n) {
int total = 0;
foreach (var i in Enumerable.Range(1, n)) { total = total + i; }
return total;
}Is it lazy? — no, it MATERIALISES#
C#'s Enumerable.Range is lazy; this one produces the whole sequence. So it is for a grid, not for a per-pixel loop:
a few hundred or a few thousand values is ordinary, and a range of hundreds of thousands allocates all of them. The
sequence is a real list — foreach it, take its .Count, or run the LINQ surface over it.
Examples#
int Count() { return Enumerable.Range(0, 5).Count; } // 5
int Empty() { return Enumerable.Range(0, 0).Count; } // 0 — well-defined, not an error
int Offset() { return Enumerable.Range(3, 4).Count; } // 3, 4, 5, 6
int EvensTo(int n) { return Enumerable.Range(0, n).Where(i => i % 2 == 0).Count; }See also#
- foreach — the loop this feeds
- for — the indexed loop a function body can use instead (a render block cannot)
- [[ui-component#render-tree]] — what a render block may contain
- Array literals — a sequence written out (
[1, 2, 3]) rather than generated