Range Types
Range types provide a way to represent and iterate over sequences of values efficiently.
Overview
The Range<T> type represents a half-open interval [start, end) that can be iterated over. It's particularly useful for:
- Looping over numeric sequences
- Generating sequences with custom steps
- Iterating backwards (counting down)
- Walking Float sequences with explicit step sizes
Creating Ranges
Use the range() function to create a range:
// Range from 0 to 5 (exclusive) - step defaults to 1
r = range(0, 5); // 0, 1, 2, 3, 4
// Range with custom step
r = range(0, 10, 2); // 0, 2, 4, 6, 8
// Counting down
r = range(10, 0, -1); // 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
// Float range
r = range(0.5, 2.0, 0.5); // 0.5, 1.0, 1.5
range() accepts either all-Integer arguments or all-Float arguments. Mixed numeric types are rejected. The optional step must be non-zero.
range is also a first-class builtin function value when a typed function is expected:
build_ints: (Integer, Integer) -> Range<Integer> = range;
build_floats: (Float, Float, Float) -> Range<Float> = range;
Type Annotation
Explicitly type your range variables:
r: Range<Integer> = range(0, 10);
r2: Range<Float> = range(0.0, 1.0, 0.25);
Iterator Interface
Ranges implement the iterator protocol with two methods:
has_next() -> Boolean
Returns true if there are more elements to iterate over:
r = range(0, 5);
while (r.has_next()) {
// Will execute 5 times
}
next() -> T
Returns the current value and advances the iterator:
r = range(0, 5);
val: Integer = r.next(); // Returns 0, iterator now at 1
val = r.next(); // Returns 1, iterator now at 2
Examples
Basic Iteration
import std.io.*;
function main(): None {
println("Counting to 5:");
r: Range<Integer> = range(0, 5);
while (r.has_next()) {
val: Integer = r.next();
println(to_string(val));
}
return None;
}
Output:
Counting to 5:
0
1
2
3
4
Even Numbers
function print_even_numbers(): None {
println("Even numbers from 0 to 10:");
r = range(0, 11, 2); // Include 10 by going to 11
while (r.has_next()) {
println(to_string(r.next()));
}
}
Countdown
function countdown(): None {
println("Launch countdown:");
r = range(10, 0, -1);
while (r.has_next()) {
println(to_string(r.next()));
}
println("Liftoff!");
}
Float Steps
function sample_curve(): None {
r: Range<Float> = range(0.0, 1.0, 0.25);
while (r.has_next()) {
println(to_string(r.next()));
}
}
Sum Calculation
function sum_range(start: Integer, end: Integer): Integer {
mut sum: Integer = 0;
r: Range<Integer> = range(start, end);
while (r.has_next()) {
sum = sum + r.next();
}
return sum;
}
// Usage
result: Integer = sum_range(1, 6); // Returns 15 (1+2+3+4+5)
Range Semantics
Half-open interval: The start is inclusive, the end is exclusive
range(0, 5)yields: 0, 1, 2, 3, 4range(5, 5)yields: (empty range)
Step direction matters:
- Positive step: iterates while current < end
- Negative step: iterates while current > end
- Zero step is invalid and is rejected
- Integer and Float ranges both follow the same half-open semantics
One-time use: A Range iterator can only be traversed once. To iterate again, create a new range.
Implementation Details
Internally, Range<T> is implemented as a struct with four fields:
start: The starting valueend: The ending value (exclusive)step: The increment/decrement amountcurrent: The current position in the iteration
The struct is heap-allocated and accessed via pointer, making range passing efficient.