`FusedIterator` marker trait and `iter::Fuse` specialization #1581
Should this discuss the consequences of an iterator implementing this trait without meeting its requirements? I don't know if it's necessary to make this an unsafe trait, but similar discussion has occurred around ExactSizeIterator.
See also #1051.
@apasel422, are you worried that someone might be relying on the behavior of Fused for safety? I can't see how this would happen in practice.
@Stebalien I'm not sure how it would happen in practice either, just pointing out some previous discussions around this matter.
@apasel422 I've added it to the unresolved questions (it's a very good question and, unfortunately, one I can't answer). Maybe if you eagerly freed or truncated something immediately after the iterator returned None and then tried to reference it later? Even if we can't come up with a good example, it might be a good idea to make this unsafe (a) to be safe and (b) to be consistent with other potential specialization traits.
| +applicable iterators and adapters. By implementing `FusedIterator`, an iterator | ||
| +promises to behave as if `Iterator::fuse()` had been called on it (i.e. return | ||
| +`None` forever after returning `None` once). Then, specialize `Fuse<I>` to be a | ||
| +no-op iff `I` implements `FusedIterator`. | ||
| + | ||
| +# Motivation | ||
| +[motivation]: #motivation | ||
| + | ||
| +Iterators are allowed to return whatever they want after returning `None` once. | ||
| +However, assuming that an iterator continues to return `None` can make | ||
| +implementing some algorithms/adapters easier. Therefore, `Fused` and | ||
| +`Iterator::fuse` exist. Unfortunately, the `Fused` iterator adapter introduces a | ||
| +noticeable overhead. Furthermore, many iterators (most if not all iterators in | ||
| +std) already act as if they were fused (this is considered to be the "polite" | ||
| +behavior). Therefore, it would be nice to be able to pay the `Fused` overhead | ||
| +iff necessary. |
|
No, I meant "if and only if necessary". Did you read an extra "not" into that sentence?
Oh, I indeed did. That being said, “nice to be able to pay the doesn’t really look right to me. /me shrugs. EDIT: I propose “only when necessary” as replacement. Sure. FYI, when writing that sentence, I didn't mean to include the "nice to be able to" in the iff. That is, I meant "pay the overhead" → "necessary to pay the overhead" ∧ "necessary to pay the overhead" -> "pay the overhead". However, I guess the second part is implied.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
|
I feel like we could just specialise exact cases we already know to be fused (that wouldn’t even need an RFC!). The only benefit of FusedIterator I see is a reduction in code duplication at the much larger drawback of increased API surface.
The RFC hides quite a bit of code. You'd have to repeat all this each time you wanted to specialize. This also prevents programmers from specializing Fuse in arbitrary ways.
I think we will have some iterator traits with much stronger "regularity" guarantees than this, maybe something like TrustedIterator. It doesn't seem needed for FusedIterator to be unsafe. Isn't it a good thing if it's a simple safe trait?
@nagisa a more general approach is to make it possible to specialize all iterator adapters (added to the RFC). Unfortunately, this has some drawbacks (also added to the RFC).
Does specialization as it exists today provide any way to omit the flag on Fuse (or make it a zero-sized type) when the inner iterator implements FusedIterator?
Yes. See rust-lang/rust#32999 (comment). Unfortunately, it's significantly more complicated and requires specializing associated types.
The libs team is leaning towards merging this as it provides a clear with for already-fused iterators and also allows the same benefits externally. Seems like a win win!
@Stebalien nah leaving all the commits as-is is fine, we actually prefer on RFCs to not squash!
I just came here via TWiR, sorry to be late to the party. +1 for the idea, but I think the name is a bit unfortunate. It might be confusing to people who know about stream fusion, because “fusion” is used here in a similar context but with a totally different meaning. (Paper that uses the term too.) I’ve seen the term ”subject to fusion” used in Haskell documentation, but the FusedIterator trait would have a completely different meaning in Rust. That said, I haven’t seen the term “stream fustion” used in Rust documentation, so perhaps it is not an issue.
It is probably too late to change this now, as Iterator::fuse exists already, and if you think about it for a while then stream fusion doesn’t make sense in the context of Rust iterators. But still, it would be nice if we could avoid the ambiguity.
This RFC adds a
FusedIteratormarker trait and specializesiter::Fuseto donothing when the underlying iterator already provides the
Fuseguarantee.See this discussion for context.
rendered
WIP PR
/cc @bluss, @Gankro