`FusedIterator` marker trait and `iter::Fuse` specialization #1581

Open
wants to merge 5 commits into from

9 participants

@Stebalien
Stebalien commented Apr 15, 2016 edited

This RFC adds a FusedIterator marker trait and specializes iter::Fuse to do
nothing when the underlying iterator already provides the Fuse guarantee.

See this discussion for context.

rendered

WIP PR

/cc @bluss, @Gankro

@apasel422
The Rust Programming Language member
apasel422 commented Apr 15, 2016 edited

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.

@Stebalien

@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.

@apasel422
The Rust Programming Language member

@Stebalien I'm not sure how it would happen in practice either, just pointing out some previous discussions around this matter.

@Stebalien Stebalien `FusedIterator` marker trait and `iter::Fuse` specialization
This RFC adds a `FusedIterator` marker trait and specializes `iter::Fuse` to do
nothing when the underlying iterator already provides the `Fuse` guarantee.
1fd4a15
@Stebalien

@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.

@nagisa nagisa and 1 other commented on an outdated diff Apr 15, 2016
text/0000-fused-iterator.md
+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.
@nagisa
nagisa added a note Apr 15, 2016

s/iff necessary/if possible/.

No, I meant "if and only if necessary". Did you read an extra "not" into that sentence?

@nagisa
nagisa added a note Apr 15, 2016 edited

Did you read an extra "not" into that sentence?

Oh, I indeed did.

That being said, iff is equivalent to logic-↔ and

“nice to be able to pay the Fused overhead” → “necessary” ∧
“necessary” → “nice to be able to pay the Fused overhead”

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
@nagisa

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.

@Stebalien

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.

@bluss

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?

@Stebalien

@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).

@hexsel hexsel referenced this pull request in rust-lang/rust Apr 16, 2016
Closed

[WIP] Implement FusedIterator #32999

@nrc nrc added the T-libs label Apr 17, 2016
@aturon aturon self-assigned this May 2, 2016
@rkjnsn

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?

@Stebalien

Yes. See rust-lang/rust#32999 (comment). Unfortunately, it's significantly more complicated and requires specializing associated types.

@aturon aturon added the I-nominated label Jul 25, 2016
@alexcrichton
The Rust Programming Language member

🔔 This RFC is now entering its week-long final comment period 🔔

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

@alexcrichton would you like me to squash?

@alexcrichton
The Rust Programming Language member

@Stebalien nah leaving all the commits as-is is fine, we actually prefer on RFCs to not squash!

@ruuda

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment