# Should we implement ExactSizeIterator for Chain?

**URL:** https://internals.rust-lang.org/t/should-we-implement-exactsizeiterator-for-chain/12556
**Category:** libs
**Created:** [June 15, 2020, 2:02am UTC](https://internals.rust-lang.org/t/should-we-implement-exactsizeiterator-for-chain/12556 "2020-06-15T02:02:53Z")
**Posts on this page:** 11
**Page:** 1

<div class="post-metadata">

### Author: ![earthengine](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/earthengine/32/2577_2.png) [@earthengine](https://internals.rust-lang.org/u/earthengine)
#### Post date: [June 15, 2020, 2:02am UTC](https://internals.rust-lang.org/t/should-we-implement-exactsizeiterator-for-chain/12556/1 "2020-06-15T02:02:53Z")

</div>

```rust
// Return none if the iterator does not contain at least 3 items, 
// and an iterator contains exactly 3 items otherwise
fn take_exact_3<T>(i: &mut impl Iterator<Item = T>) 
    -> Option<impl ExactSizeIterator<Item = T>> {
    let t1 = i.next()?;
    let t2 = i.next()?;
    let t3 = i.next()?;
    Some(once(t1).chain(once(t2)).chain(once(t3)))
}

```

The above didn't compile because `Chain<T1, T2>` didn't implement `ExactSizeIterator` even when `T1` and `T1` both implements it.

In theory though, if `T1` and `T2` all have exact sizes, the chained iterator should also have exact size.

Is this a missing piece of the standard library? I am looking forward to write a generic macro for those `take_exact_n` functions.

---

<div class="post-metadata">

### Author: ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)
#### Post date: [June 15, 2020, 2:22am UTC](https://internals.rust-lang.org/t/should-we-implement-exactsizeiterator-for-chain/12556/2 "2020-06-15T02:22:53Z")

</div>

I believe the main reason it doesn't have this already is that adding two lengths may overflow.

---

<div class="post-metadata">

### Author: ![earthengine](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/earthengine/32/2577_2.png) [@earthengine](https://internals.rust-lang.org/u/earthengine)
#### Post date: [June 15, 2020, 2:34am UTC](https://internals.rust-lang.org/t/should-we-implement-exactsizeiterator-for-chain/12556/3 "2020-06-15T02:34:19Z")

</div>

It is a bit weird since we can create `ExactSizeIterator` with 0 or 1 items, but we couldn't even create one that have exactly 2/3 items unless defining a newtype.

In general though, rust does not prevent this kind of errors: if you access an `Vec` with out-of-bound index you panic. So I don't know why we couldn't do the same here - if the user access the `len` method and it is overflowed, just let it panic.

---

<div class="post-metadata">

### Author: ![197g](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/197g/32/7276_2.png) [@197g](https://internals.rust-lang.org/u/197g)
#### Post date: [June 15, 2020, 4:35am UTC](https://internals.rust-lang.org/t/should-we-implement-exactsizeiterator-for-chain/12556/4 "2020-06-15T04:35:43Z")

</div>

Interestingly, `a.chain(b).take(usize::MAX)` would be able to be `ExactSizeIterator` but that would require all kinds of specialization. I wonder if the precedent here is enough to introduce this as its own concept?

---

<div class="post-metadata">

### Author: ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)
#### Post date: [June 15, 2020, 7:12am UTC](https://internals.rust-lang.org/t/should-we-implement-exactsizeiterator-for-chain/12556/5 "2020-06-15T07:12:55Z")

</div>

You can go a lot further with all kinds of logic like this.

For example this one is always of length 10, no matter what kind of iterator `i` is:

```rust
once(x).chain(i).cycle().take(10)

```

Edit: This example would be particularly hard to archieve based on the type system alone since the _type_ of the iterator that `once` produces also allows for the iterator to be empty (after `next` was called).

---

<div class="post-metadata">

### Author: ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)
#### Post date: [June 15, 2020, 7:56pm UTC](https://internals.rust-lang.org/t/should-we-implement-exactsizeiterator-for-chain/12556/6 "2020-06-15T19:56:13Z")

</div>

> [@earthengine](#):
>
> In theory though, if `T1` and `T2` all have exact sizes, the chained iterator should also have exact size.

That's true in theory, where we have infinite-precision integers. But it's not true in practice where we only have `usize`.

This is the very nuanced difference between the rules for `ExactSizeIterator` -- where the len must be exact -- and `TrustedLen` -- where the size hint is allowed to be infinite -- which is why their rules for various adapters are different.

---

<div class="post-metadata">

### Author: ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)
#### Post date: [June 15, 2020, 8:47pm UTC](https://internals.rust-lang.org/t/should-we-implement-exactsizeiterator-for-chain/12556/7 "2020-06-15T20:47:27Z")

</div>

Is panicking acceptable in such case? Would presence of panic negatively affect optimizations?

Maybe it could saturate? Behaving like `.take(usize::MAX)` shouldn't be limiting for practical applications, since it's already problematic to process this many items on 32-bit machines, and outright impossible on 64-bit.

And it can never overflow with any collections that are actually in memory, because by definition there's not enough address space for two collections to be that big.

---

<div class="post-metadata">

### Author: ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)
#### Post date: [June 15, 2020, 8:53pm UTC](https://internals.rust-lang.org/t/should-we-implement-exactsizeiterator-for-chain/12556/8 "2020-06-15T20:53:04Z")

</div>

I'm going to lazily reply with links... 😅

> <https://github.com/rust-lang/rust/issues/34433>
>
> When both iterators of the chain implement ExactSizeIterator, the chain itself should implement that trait as well.

> <https://github.com/rust-lang/rust/pull/66531>

---

<div class="post-metadata">

### Author: ![mjw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mjw/32/6108_2.png) [@mjw](https://internals.rust-lang.org/u/mjw)
#### Post date: [June 16, 2020, 7:38am UTC](https://internals.rust-lang.org/t/should-we-implement-exactsizeiterator-for-chain/12556/9 "2020-06-16T07:38:19Z")

</div>

This response makes me think that Rust would benefit from having a technical FAQ.

---

<div class="post-metadata">

### Author: ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)
#### Post date: [June 19, 2020, 12:23am UTC](https://internals.rust-lang.org/t/should-we-implement-exactsizeiterator-for-chain/12556/10 "2020-06-19T00:23:46Z")

</div>

Well, I bet a PR to describe this in `Chain`'s docs would be welcome.

---

<div class="post-metadata">

### Author: ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)
#### Post date: [September 17, 2020, 12:23am UTC](https://internals.rust-lang.org/t/should-we-implement-exactsizeiterator-for-chain/12556/11 "2020-09-17T00:23:58Z")

</div>

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