Pre-RFC: Fixing Range by 2027

+1 to basically everything in the original post. I am very pro removing Iterator methods on Range* and making one go through into_iter() (or even iter() as a slightly shorter spelling, although that might be confusing since it probably would not hand out references the way other iter() methods do).

One thing I would like to see in Rust, somewhat related to this, is a single (Into)Iterator type more flexible than Range. Sometimes you want to put multiple ranges in an array, but some are stepped, some are reversed… you end up needing to use Box<dyn Iterator<Item=i32>> or similar just to store them in the same container. I'd love to have a type that can represent iteration over arbitrary arithmetic sequences. Something isomorphic to this:

enum Stepper {
    Infinite,
    Finite { count: usize },
}

struct ArithSeq<T: Step> {
    start: T,
    step: T,
    stepper: Stepper,
}

To construct one, you'd want methods to fill in the right values of the three fields based on more “human” values of the sequences (e.g., start, stop?, step). (Implementation left to the reader.)

Sure, that's fine, and it makes sense as a crate.

I don't think it needs to be in core, though. And it's definitely not what <NewRange as IntoIterator>::IntoIter will be, since extra flexibility has perf cost.

2 Likes

I thought that there was a lot of special-cased code in StepBy and other places to make arithmetic progressions efficient (because of issues like 59281). Would putting this functionality in a crate mean a loss in performance?

I fear this change could be a bit too disruptive, as iterating over a range of numbers is such a basic thing the language provides. Things like (from..to).rev() or (from..to).map(...) are very basic constructs that are used all over the place, and potentially breaking those and needing to add .into_iter() calls in the middle seems like a huge cost. Even if an individual project could be upgraded with cargo fix or some similar automation, still this would be a significant semantic change between editions, and a mental burden of having a basic construct like (from..to).rev() changing its meaning depending on the Rust edition.

And of course things that cannot be easily updated by cargo fix, like online answers, blog posts, or old projects, might never be updated and thus add to a feeling of language version fragmentation.

So, could this be achieved in a less disruptive way? If the goal is to have a range-like object that is Copy (but not Iterator!) and can be conveniently stored in structs and passed around, couldn't a new type be added for this purpose and have a method of Range that would return a value of this new type, e.g. (1..10).to_inverval()? (Or even a From impl so that a Range could be .into()ed into this new type)

To be clear, in the RFC I am working on, the new range types will have inherent methods for common iterator methods like map and rev.

This is a risk with any edition change. I think in this case, we can mitigate the risk with the following:

  • good documentation
  • helpful error messages
  • having those inherent methods for common cases

I don't really see that much disruption. With the inherent methods, most code will stay the same. And in most other cases, all that will be necessary is changing Iterator to IntoIterator, adding .into_iter(), or converting to the old type.

12 Likes

Posted the RFC: New range types for Edition 2024 by pitaj · Pull Request #3550 · rust-lang/rfcs · GitHub

11 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.