Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't use DoubleEndedIterator for inclusive ranges #66195

Open
kacejot opened this issue Nov 7, 2019 · 4 comments
Open

Can't use DoubleEndedIterator for inclusive ranges #66195

kacejot opened this issue Nov 7, 2019 · 4 comments
Labels
A-iterators Area: Iterators C-enhancement Category: An issue proposing an enhancement or a PR with one. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@kacejot
Copy link

kacejot commented Nov 7, 2019

Code:

fn main() {
    let size = 10;
    let h = size / 2;
    let _iter = (-h..=h).step_by(size as usize).rev();
}

Error:

error[E0277]: the trait bound `std::ops::RangeInclusive<i32>: std::iter::ExactSizeIterator` is not satisfied
 --> src/main.rs:4:48
  |
4 |     let iter = (-h..=h).step_by(size as usize).rev();
  |                                                ^^^ the trait `std::iter::ExactSizeIterator` is not implemented for `std::ops::RangeInclusive<i32>`
  |
  = help: the following implementations were found:
            <std::ops::RangeInclusive<i16> as std::iter::ExactSizeIterator>
            <std::ops::RangeInclusive<i8> as std::iter::ExactSizeIterator>
            <std::ops::RangeInclusive<u16> as std::iter::ExactSizeIterator>
            <std::ops::RangeInclusive<u8> as std::iter::ExactSizeIterator>
  = note: required because of the requirements on the impl of `std::iter::DoubleEndedIterator` for `std::iter::StepBy<std::ops::RangeInclusive<i32>>`

I think Rust is not getting safer without ExactSizeIterator implementation for RangeInclusive. The behavior like the one above is not obvious for average Rust coder. Moreover, the workaround exists:

fn main() {
    let size = 10;
    let h = size / 2;
    let _iter = (-h..h+1).step_by(size as usize).rev();
}

related: #36386

@jonas-schievink jonas-schievink added A-iterators Area: Iterators C-enhancement Category: An issue proposing an enhancement or a PR with one. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. labels Nov 7, 2019
@n3ziniuka5
Copy link

n3ziniuka5 commented Apr 21, 2023

To give some context, I am currently learning Rust via Jetbrain Academy, which is an adaptation of the rustlings course.

In the part about Ranges, they provide this code as an example

fn main() {
    for number in (1..4).rev() {
        println!("{}!", number);
    }
    println!("LIFTOFF!!!");
}

I started toying with it, modified the range to (1..4).step_by(2).rev(), then I tried using an inclusive range - (1..=4).step_by(2).rev(), and it errored out. To my surprise, if I changed the order of step_by and rev calls, it started working again - (1..=4).rev().step_by(2). It also didn't complain if I used i16 - (1_i16..=3_i16).step_by(2).rev().

I understand that this compromise was made due to #36386, but as someone who's just learning rust now, the issue I ran into was a massive WTF moment for me, probably a much bigger one than if I had tried to do (0...usize::max_value()).len() and it panicked.

I think fixing this issue could help Rust with its goal to flatten the learning curve.

@SUPERCILEX
Copy link
Contributor

I just ran into this too, pretty annoying.

@SUPERCILEX
Copy link
Contributor

Not going to happen because of

// These are incorrect per the reasoning above,
// but removing them would be a breaking change as they were stabilized in Rust 1.0.0.
// So e.g. `(0..66_000_u32).len()` for example will compile without error or warnings
// on 16-bit platforms, but continue to give a wrong result.
u32
i32
}
unsafe_range_trusted_random_access_impl! {
usize u8 u16
isize i8 i16
}
#[cfg(target_pointer_width = "32")]
unsafe_range_trusted_random_access_impl! {
u32 i32
}
#[cfg(target_pointer_width = "64")]
unsafe_range_trusted_random_access_impl! {
u32 i32
u64 i64
}
range_incl_exact_iter_impl! {
u8
i8
// These are incorrect per the reasoning above,
// but removing them would be a breaking change as they were stabilized in Rust 1.26.0.
// So e.g. `(0..=u16::MAX).len()` for example will compile without error or warnings
// on 16-bit platforms, but continue to give a wrong result.
u16
i16
as briefely discussed in the 2024 range rfc: https://github.com/pitaj/rfcs/blob/new-range/text/3550-new-range.md#iterator-types

@SUPERCILEX
Copy link
Contributor

I wonder if it makes sense to panic in ExactSizeIterator if the range is too big for the platform. Pretty sure that makes the type unusable though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-iterators Area: Iterators C-enhancement Category: An issue proposing an enhancement or a PR with one. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants