# Iterator Namepocalypse
*Itertools* is a Rust crate that extends Rust's `Iterator`s with more than 100 additional methods. The crate is both one of Rust's oldest (in development since Jul 28, 2014), most depended upon (~4,300 direct dependants), and most downloaded (115+ million downloads).
The Itertools mission is two-fold:
- to make the experience of working with iterators more pleasant
- to serve as a laboratory for future improvements to Rust's standard library `Iterator` trait
This document addresses a persistent name-conflict issue between Itertools and the Rust standard library that undermines this mission.
## Technical Context
The Itertools crate implements the *extension trait* design pattern. In this pattern, a library-defined trait is used to add additional methods to third-party code.
Concretely, Itertools extends the `Iterator` trait defined by the Rust standard library:
```rust
/* in `std::iter` */
trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
/* additional methods */
}
```
It does so by defining a trait called `Itertools` that extends `Iterator` and is implemented for all types implementing `Iterator`:
```rust
/* in `itertools` */
// `Itertools` extends `Iterator`
trait Itertools: Iterator {
// And provides methods, like `flatten`, that are
// not available on `Iterator.
fn flatten(self) -> Flatten<Self> ⓘ
where
Self: Sized,
Self::Item: IntoIterator
{
/* ... */
}
}
// These methods are made available by providing a
// blanket-implementation of `Itertools` for all things
// that implement `Iterator`.
impl Itertools for I
where
I: Iterator
{}
```
### Fatal Flaw
The trait extension pattern used by Itertools falters if any other applicable traits define the same methods. For instance, if `Iterator` were to *also* define a `flatten` method, Rust would begin to produce compilation errors at all `.flatten()` call-sites.
## Historical Context
In 2018, [a PR was opened](https://github.com/rust-lang/rust/pull/48115) on rust-lang/rust to promote `Itertools::flatten` into the standard library's `Iterator` trait. Upon release, this (unstable) change caused rustc to produce a compilation error at all existing callsites of `.flatten()`.
Three counter measures were adopted, and by the time `flatten` was stabilized, [only 11 crates](https://github.com/rust-lang/rust/pull/51511#issuecomment-397239344) were broken directly by the addition (and 26 crates, transitively).
#### Resolve unstable methods with lower priority and warn about future incompatibility.
Rust [was modified](https://github.com/rust-lang/rust/pull/48552) to depriotitize and warn (rather than error) in cases where the conflicting method is unstable.
This change creates a buffer period in which customers (provided that they are using an up-to-date Rust) receive a warning that breakage is impending.
#### Add free-function alternatives to `Itertools` methods.
Itertools began to add 'free' function alternatives to its methods. Concerned or affected users are encouraged to use these functions instead of `Itertools` method calls, since these functions are unaffected by naming conflicts. These functions are generally less ergonomic than their method counterparts.
#### Discourage potentially-conflicting new contributions to `Itertools`.
Itertools adopted a policy of discouraging new contributions that could conflict with future additions to `Iterator`.
## Naming Conflicts Continue
In 2020, [a PR was opened](https://github.com/rust-lang/rust/pull/79479) on rust-lang/rust to promote `Itertools::intersperse` into the standard library's `Iterator` trait.
This PR was merged and stabilized without substantial consideration of the breakage it could cause. The stabilization was reverted [upon discovery](https://github.com/rust-lang/rust/issues/88967) that it broke 59 direct (and 538 indirect) dependents of Itertools.
Although this kind of breakage is expressly allowed by Rust's compatibility guarantees, the Rust Library Team takes, in practice, a more conservative position and tries to avoid breakage whenever possible. The stabilization of `intersperse` remains incomplete.
## Corrective Action
The persistent risk of naming conflicts between `Iterator` and `Itertools` undermines the maintenance of both of these projects; e.g.:
- The Rust Library Team is unable to stabilize much-desired features in `Iterator` for fear of causing widespread breakage.
- The Itertools Team is unable to accept new useful contributions that could, plausibly, become future additions to `Iterator`.
### Rust: Supertrait Item Shadowing
[*RFC2845: Supertrait Item Shadowing*](https://github.com/rust-lang/rfcs/pull/2845) proposes altering Rust's method resolution to (mostly) eliminate this class of compiler errors. Specifically, Rust would instead treat same-named items in sub-traits as 'shadowing' their counterparts in super-traits. This RFC was accepted in September 2021, but has not yet been implemented.
If implemented, the Rust Library Team could freely promote items from `Itertools` into `Iterator` without causing breakage.
There would remain some risk that users would get 'stuck' on the sub-optimal implementations provideded by `Itertools` (since standard library iterator adapters can make optimizations that crates cannot), but Itertools would mitigate this by periodically removing items that have been promoted into the standard library.
### Itertools: Rename Methods
Itertools could prefix its methods with `it_`, making future conflicts with `Iterator` far less likely. This approach could be readily implemented by `Itertools`, but would cause a brief period of breakage (or, at least, myriad compiler warnings) for *all* users of Itertools.
## Next Steps
RFC2845 has every advantage over *Rename Methods*, except that it would surely take longer to release. However, given its advantages (namley: no breakage for itertools users), we should at least investigate implementing it. I asked Michael Goulet (@compiler-errors) for his impression on feasibility: A few (probably amendable) corner cases aside, he believes it would not be too difficult to implement.
If it proves to be too difficult, we can always *Rename Methods*.