In a ranged loop, why is the start index inclusive of the end index?

Given a ranged loop, It is my understanding that the start is inclusive while the end is exclusive.

I take this to mean that the start index should always have a valid entry like this

~/Desktop/temp/bench [1] $ tail -n 7  main.zig && zig build-exe main.zig && ./main 
pub fn main() !void {
    const array = [_]usize{0};
    print("Item: {d}\n", .{array[0]});
    for (array[0..], 0..) |n, i| {
        print("{d}: {d}\n", .{ i, n });
    }
}
Item: 0
0: 0

However, in this case the start index is not a valid entry, My intuition (given the last case below) tells me that this should be an error. But it compiles and runs without a problem, even though the start index of the iteration is not iterated over.

~/Desktop/temp/bench $ tail -n 7  main.zig && zig build-exe main.zig && ./main 
pub fn main() !void {
    const array = [_]usize{0};
    print("Item: {d}\n", .{array[0]});
    for (array[1..], 0..) |n, i| {
        print("{d}: {d}\n", .{ i, n });
    }
}
Item: 0

This last case made me question the case above. In this case the start index is also invalid, however, unlike the previous case, the compiler does throw an error.

~/Desktop/temp/bench $ tail -n 7  main.zig && zig build-exe main.zig && ./main 
pub fn main() !void {
    const array = [_]usize{0};
    print("Item: {d}\n", .{array[0]});
    for (array[2..], 0..) |n, i| {
        print("{d}: {d}\n", .{ i, n });
    }
}
main.zig:55:16: error: start index 2 is larger than end index 1
    for (array[2..], 0..) |n, i| {
               ^
referenced by:
    callMain [inlined]: /home/jlarator/bin/zig/lib/std/start.zig:698:59
    callMainWithArgs [inlined]: /home/jlarator/bin/zig/lib/std/start.zig:638:20
    posixCallMainAndExit: /home/jlarator/bin/zig/lib/std/start.zig:590:38
    2 reference(s) hidden; use '-freference-trace=5' to see all references

The compiler errors out when the start index is greater than the end index, but shouldn’t it also error out when it is equal to it? given that the access would also be illegal?

Is there a good reason for this behavior?

array[1..], 0..

Above, the inferred range is 1..1 which is still in array’s bound of 0..1. This behavior is desired when you want to split a slice at an index n and have tail = array[n..] where tail could be empty

array[2..], 0..

Here, the inferred range would have to start at 2.., which is immediately out of bound of 0..1 and warrants a compiler error

1 Like