# Why there is no windows for iterators?

**URL:** <https://users.rust-lang.org/t/why-there-is-no-windows-for-iterators/65515>\
**Category:** uncategorized\
**Created:** [October 4, 2021, 1:58pm UTC](https://users.rust-lang.org/t/why-there-is-no-windows-for-iterators/65515 "2021-10-04T13:58:49Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![amarao](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/amarao/32/11182_2.png) [@amarao](https://users.rust-lang.org/u/amarao)\
**Post date:** [October 4, 2021, 1:58pm UTC](https://users.rust-lang.org/t/why-there-is-no-windows-for-iterators/65515/1 "2021-10-04T13:58:49Z")

</div>

I found that there is no `.windows()` for iterators, which is sound strange to me. I can do `windows()` over a slice or a Vec, but I can't do it over an iterator. I'm not sure I can write my own with ease, but (without trying) I suspect it should be easy. All it needs is to implement a `get` function and store some circular fixed size buffer in `Windows` structure.

Are there some real reasons for not having `windows` for iterator? Some code would become a bliss it it was there...

---

<div class="post-metadata">

**Author:** ![cole-miller](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/cole-miller/32/16722_2.png) [@cole-miller](https://users.rust-lang.org/u/cole-miller)\
**Post date:** [October 4, 2021, 2:01pm UTC](https://users.rust-lang.org/t/why-there-is-no-windows-for-iterators/65515/2 "2021-10-04T14:01:30Z")

</div>

> [@amarao](#):
>
> All it needs is to implement a `get` function and store some circular fixed size buffer in `Windows` structure.

The trouble with this is that the value returned from `next` would need to borrow from the iterator itself, which is not allowed by the signature `fn next(&mut self) -> Option<Self::Item>`. A "lending iterator" using a [generic associated type](https://blog.rust-lang.org/2021/08/03/GATs-stabilization-push.html) could have such a method, though.

---

<div class="post-metadata">

**Author:** ![Cerber-Ursi](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/cerber-ursi/32/8315_2.png) [@Cerber-Ursi](https://users.rust-lang.org/u/Cerber-Ursi)\
**Post date:** [October 4, 2021, 2:02pm UTC](https://users.rust-lang.org/t/why-there-is-no-windows-for-iterators/65515/3 "2021-10-04T14:02:14Z")

</div>

There's [`tuple_windows`](https://docs.rs/itertools/0.10.1/itertools/trait.Itertools.html#method.tuple_windows) in `itertools`, which is probably the standard de-facto for the cases around iteration which aren't polished enough to fulfill the standard library stability guarantee.

---

<div class="post-metadata">

**Author:** ![amarao](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/amarao/32/11182_2.png) [@amarao](https://users.rust-lang.org/u/amarao)\
**Post date:** [October 4, 2021, 2:10pm UTC](https://users.rust-lang.org/t/why-there-is-no-windows-for-iterators/65515/4 "2021-10-04T14:10:13Z")

</div>

I don't get it.

Some crazy pseudo-code for windows(2), for returning first two elements. I skip whole "rolling" part here, but the function signature does not prevent me from calling inner iterator few times:

```rust
impl Window.. {
    fn next (&mut self) -> Option<Item>{
       self.one = self.inner_iter.next();
       self.two = self.inner_iter.next();
       if self.one.is_some() && self.two.is_some(){
           return Some([self.one.unwrap(), self.two.unwrap()])
       }
}
```

---

<div class="post-metadata">

**Author:** ![cole-miller](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/cole-miller/32/16722_2.png) [@cole-miller](https://users.rust-lang.org/u/cole-miller)\
**Post date:** [October 4, 2021, 2:13pm UTC](https://users.rust-lang.org/t/why-there-is-no-windows-for-iterators/65515/5 "2021-10-04T14:13:05Z")

</div>

This works because you're returning an owned, newly-constructed array from `next`, not a reference to an internally stored buffer. As soon as you try to do the second thing you will get an error.

The slice type `[T]` gets around this because the items are already stored contiguously in memory, so it can return references to that memory region instead of a buffer owned by the iterator. For general iterators there's no guarantee that the items are stored contiguously somewhere.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/kornel/32/4823_2.png) [@kornel](https://users.rust-lang.org/u/kornel)\
**Post date:** [October 4, 2021, 2:16pm UTC](https://users.rust-lang.org/t/why-there-is-no-windows-for-iterators/65515/6 "2021-10-04T14:16:16Z")

</div>

The `Iterator` interface guarantees that this is _always_ valid:

```rust
let a = iter.next().unwrap();
let b = iter.next();
drop(iter);
use_both(a,b);

```

If you allowed windows, it would allow mutable aliasing:

```rust
let mut iter = x.iter_mut().windows(2);
let a = iter.next()?;
let b = iter.next()?;
drop(iter);
/// a[1] aliases b[0], nasal demons release

```

and/or wouldn't match lifetimes that `Iterator` promises to be valid, failing compilation or breaking the safety of the borrow checker.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/scottmcm/32/4286_2.png) [@scottmcm](https://users.rust-lang.org/u/scottmcm)\
**Post date:** [October 4, 2021, 8:08pm UTC](https://users.rust-lang.org/t/why-there-is-no-windows-for-iterators/65515/7 "2021-10-04T20:08:00Z")

</div>

See this for a bunch of conversation about why `windows` is awkward, but a proposed API to offer instead:

~~([Add `Iterator::map_windows` by LukasKalbertodt · Pull Request #82413 · rust-lang/rust · GitHub](https://github.com/rust-lang/rust/pull/82413))~~

EDIT 2023 looks like it landed in nightly, see

> <https://github.com/rust-lang/rust/issues/87155>
>
> \<!--
> Thank you for creating a tracking issue!
> 
> Tracking issues are for tracki…ng a feature from implementation to stabilization.
> 
> Make sure to include the relevant RFC for the feature if it has one.
> 
> If the new feature is small, it may be fine to skip the RFC process. In that
> case, you can use use \`issue = "none"\` in your initial implementation PR. The
> reviewer will ask you to open a tracking issue if they agree your feature can be
> added without an RFC.
> \--\>
> 
> Feature gate: \`#!\[feature(iter\_map\_windows)\]\`
> 
> This is a tracking issue for \`Iterator::map\_windows\`:
> 
> \> Calls the given function \`f\` for each contiguous window of size \`N\` over \`self\` and returns an iterator over the outputs of \`f\`.
> \>
> \> In the following example, the closure is called three times with the arguments \`&\['a', 'b'\]\`, \`&\['b', 'c'\]\` and \`&\['c', 'd'\]\` respectively.
> \>
> \> \`\`\`
> \> #!\[feature(iter\_map\_windows)\]
> \>
> \> let strings = "abcd".chars()
> \> .map\_windows(|\[x, y\]| format!("{}+{}", x, y))
> \> .collect::\<Vec\<String\>\>();
> \>
> \> assert\_eq!(strings, vec!\["a+b", "b+c", "c+d"\]);
> \> \`\`\`
> 
> \### Public API
> 
> \`\`\`rust
> impl Iterator {
> fn map\_windows\<F, R, const N: usize\>(self, f: F) -\> MapWindows\<Self, F, N\>
> where
> Self: Sized,
> F: FnMut(&\[Self::Item; N\]) -\> R;
> }
> 
> struct MapWindows\<I: Iterator, F, const N: usize\> { ... }
> 
> impl\<I, F, R, const N: usize\> Iterator for MapWindows\<I, F, N\>
> where
> I: Iterator,
> F: FnMut(&\[I::Item; N\]) -\> R;
> 
> impl\<I: Iterator + fmt::Debug, F, const N: usize\> fmt::Debug for MapWindows\<I, F, N\>;
> \`\`\`
> 
> \### Steps / History
> 
> \- \[\] ~~Implementation: #82413~~
> \- \[\] Implementation: #94667
> \- \[x\] Optimize with buffer of size \`2 \* N\`
> \- \[\] Any other iterator-related traits?
> - \[\] \`DoubleEndedIterator\`
> - \[\] \`FusedIterator\`
> - \[\] \`TrustedLen\`
> \- \[\] Compile fail on N=0, rather than panic
> \- \[\] Final comment period (FCP)
> \- \[\] Stabilization PR
> 
> \<!--
> Once the feature has gone through a few release cycles and there are no
> unresolved questions left, the feature might be ready for stabilization.
> 
> If this feature didn't go through the RFC process, a final comment period
> (FCP) is always needed before stabilization. This works as follows:
> 
> A library API team member can kick off the stabilization process, at which point
> the rfcbot will ask all the team members to verify they agree with
> stabilization. Once enough members agree and there are no concerns, the final
> comment period begins: this issue will be marked as such and will be listed
> in the next This Week in Rust newsletter. If no blocking concerns are raised in
> that period of 10 days, a stabilzation PR can be opened by anyone.
> \--\>
> 
> \### Unresolved Questions
> 
> \- \`&\[I::Item; N\]\` vs \`ArrayView\<'\_, I::Item, N\>\` https://github.com/rust-lang/rust/issues/87155#issuecomment-1447603360

> [@amarao](#):
>
> I skip whole "rolling" part here

That makes it `chunks`, not `windows`, which makes a _huge_ difference. `chunks` only needs to give access to each item once, which means that no-copy move-only semantics works great. `windows` is much harder -- note that slices have `chunks` _and_ `chunks_mut`, but only `windows` no `windows_mut`.

---

<div class="post-metadata">

**Author:** ![quinedot](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/quinedot/32/17693_2.png) [@quinedot](https://users.rust-lang.org/u/quinedot)\
**Post date:** [October 4, 2021, 8:22pm UTC](https://users.rust-lang.org/t/why-there-is-no-windows-for-iterators/65515/8 "2021-10-04T20:22:24Z")

</div>

[Temporarily opting-in to shared mutation](https://ryhl.io/blog/temporary-shared-mutation/) lets you use `windows` and similar slice iterators in a mutable (albeit more limited) fashion.

---

<div class="post-metadata">

**Author:** ![dbr](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/dbr/32/14608_2.png) [@dbr](https://users.rust-lang.org/u/dbr)\
**Post date:** [October 7, 2021, 1:06am UTC](https://users.rust-lang.org/t/why-there-is-no-windows-for-iterators/65515/9 "2021-10-07T01:06:09Z")

</div>

Would the [`Peekable`](https://doc.rust-lang.org/std/iter/struct.Peekable.html) trait work for this in some limited (`.windows(2)`) cases?

---

<div class="post-metadata">

**Author:** ![quinedot](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/quinedot/32/17693_2.png) [@quinedot](https://users.rust-lang.org/u/quinedot)\
**Post date:** [October 7, 2021, 2:11am UTC](https://users.rust-lang.org/t/why-there-is-no-windows-for-iterators/65515/10 "2021-10-07T02:11:30Z")

</div>

I don't see much of a benefit. `next()` still only returns one element and you still can't use `for` like you can with windows.

```rust
let mut iter = v.iter_mut().peekable();
while let Some(one) = iter.next() {
    if let Some(two) = iter.peek_mut() {
       // Do stuff with `one` and `*two`
    }
}
// vs.
let mut iter = v.iter_mut();
if let Some(mut one) = iter.next() {
    while let Some(two) = iter.next() {
        // Do stuff with `one` and `two`, then
        one = two
    }
}

```

(And a potential downside that the peek has a limited lifetime ala lending iterators.)

---

<div class="post-metadata">

**Author:** ![system](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/system/32/51372_2.png) [@system](https://users.rust-lang.org/u/system)\
**Post date:** [January 5, 2022, 2:12am UTC](https://users.rust-lang.org/t/why-there-is-no-windows-for-iterators/65515/11 "2022-01-05T02:12:19Z")

</div>

Closed on January 5, 2022, 2:12am UTC

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.
