> Ranges can only exist as an argument to a for loop. This means that you can’t store them in variables
I am confident this is a mistake. Every time you make a new kind of "thing" in your language somebody will want to do all the same stuff with it that they did with the other things, such as integers, ie in this case store a range in a variable. Ideally you'd just always be able to do that, see Lisp, but it can get very unwieldy, thus this is a reason to avoid making new kinds of thing so the issue doesn't arise.
C++ chooses to actually do the heavy lifting here, which is why std::format (and its inspiration fmt::format) was such an enormous undertaking -- C++ can express the idea of a function which takes a variable number of arguments and yet all those arguments are independently type checked at compile time, not via compiler magic but just as a normal feature of the language. This is an enormous labour, and because they don't have any way to fix syntax issues the resulting problem accumulate forever in their language so I cannot recommend it as a course to other languages. It's like the Pyramids, do not build giant stone tombs for your leaders, this is a bad idea and your society should not copy it - however, the ancient Egyptians already did build giant stone tombs and they're pretty awesome to look at.
Anyway, Rust chose to make its half-open range type std::ops::Range an actual type which you can store in a variable, pass to functions, modify etc. as well as using it in a for loop. Obviously don't copy Rust here exactly, for one thing Range should probably be IntoIterator, not an Iterator itself if they had it over, but you will wish this was an ordinary type in your language, so, just do it now.
let a = 0..4; // The Range starting at zero and (non-inclusively) ending at four.
The problem is that zig's designers apparently don't want to introduce an iterator abstraction, hence the frankenstein-ing of the for loop instead.
Though in fairness getting an iterator abstraction to the same efficiency as a for loop requires pretty brutal optimisations, frankensteining your for loop, a lot less so.
I don't know how ranges are implemented now (and I'm too lazy to check right now) but It's entirely possible zig's ranges could wind up as comptime-only values.
Then you could pass them around, but only at comptime, which will achieve many of the things you expect.
There's also nothing stopping you from creating an iterator interface in userland.
> There's also nothing stopping you from creating an iterator interface in userland.
I don't see any way you could do that with these ranges, and I'm unsure to what extent you can do this for any of the built-in types without their co-operation. If it needs co-operation then there's actually a lot stopping you from creating a useful iterator interface.
Also there are a bunch of plausible iterator APIs ranging from a very narrow API like Rust's Iterator trait to something as broad as C++ "iterators" which are effectively just (sometimes magic) pointers.
I am confident this is a mistake. Every time you make a new kind of "thing" in your language somebody will want to do all the same stuff with it that they did with the other things, such as integers, ie in this case store a range in a variable. Ideally you'd just always be able to do that, see Lisp, but it can get very unwieldy, thus this is a reason to avoid making new kinds of thing so the issue doesn't arise.
C++ chooses to actually do the heavy lifting here, which is why std::format (and its inspiration fmt::format) was such an enormous undertaking -- C++ can express the idea of a function which takes a variable number of arguments and yet all those arguments are independently type checked at compile time, not via compiler magic but just as a normal feature of the language. This is an enormous labour, and because they don't have any way to fix syntax issues the resulting problem accumulate forever in their language so I cannot recommend it as a course to other languages. It's like the Pyramids, do not build giant stone tombs for your leaders, this is a bad idea and your society should not copy it - however, the ancient Egyptians already did build giant stone tombs and they're pretty awesome to look at.
Anyway, Rust chose to make its half-open range type std::ops::Range an actual type which you can store in a variable, pass to functions, modify etc. as well as using it in a for loop. Obviously don't copy Rust here exactly, for one thing Range should probably be IntoIterator, not an Iterator itself if they had it over, but you will wish this was an ordinary type in your language, so, just do it now.