The language spec recommends using range syntax to iterate over ranges and gives the following example:
var sum3 : usize = 0;
for (0..5) |i| {
sum3 += i;
}
try expect(sum3 == 10);
This works great when you’re working with usize integers, but if you have another integer type it becomes awkward:
const a: isize = 1;
const b: isize = 10;
var sum: isize = 0;
for (a..b) |i| {
sum += i; // error: incompatible types: 'isize' and 'usize'
}
try expect(sum == 45);
And of course in this example you could use @intCast()
, but I could also imagine situations where the lower bound can be a negative integer, or where bounds are u64 or something.
Is there a reason why the the type of i
isn’t simply @TypeOf(a, b)
?
The for loop mainly exists to iterate over slices. For example:
const slice: []u8 = ...
for(slice[a..b], a..b) |val, index| {...}
That’s why for(a..b)
has the same restrictions as slice[a..b]
, that being:
b
must be greater than or equal to a
a
and b
must fit inside a usize
(→ only positive values are allowed)
Note that your example only works like this because a
and b
are comptime known. If they are runtime-known isize
you will get an earlier compiler error:
var a: isize = 1;
_ = &a;
var b: isize = 10;
_ = &b;
var sum: isize = 0;
for (a..b) |i| { // error: expected type 'usize', found 'isize'
sum += i;
}
So the lower bound can’t be negative.
Here is a proposal for that on github: Proposal: Infer type on ranged for loops from the type of the range values instead of defaulting to usize · Issue #14704 · ziglang/zig · GitHub
It was rejected by Andrew due to implementation problems.
5 Likes