Why doesn’t std::iter::Flatten implement std::iter::FusedIterator regardless if the outer or inner iterators do?

Assuming I am correctly reading the source code for std::iter::Flatten, the outer iterator is always std::iter::Iterator::fused. Furthermore, since the calls are simply redirected to an internal type, FlattenCompat, and it stops iterating any inner iterator as soon as it returns None, then this means it will forever return None as soon as it returns None once. Since this is the sole requirement for implementing std::iter::FusedIterator, I find it bizarre that it chooses not to implement that trait. Is this simply for forwards compatibility (i.e., to allow the code to be changed such that it doesn’t have this behavior)?

It doesn't actually fuse when calling backiter (see this line)

2 Likes

Yeah, only the outer iterator is ever fused; but I thought—incorrectly it appears—that backiter does not matter. Can you hack up a counterexample to my claim to give me something “concrete” to play with? I keep failing in creating my own iterator type that when flattened does not always produce None after the first None. I will keep trying though. If my claim is wrong though, then it should be easy to construct a counterexample. For some sad reason, my brain is struggling though.

Furthermore, I find it bizarre that adding the std::iter::FusedIterator bound on the outer iterator is enough for std::iter::Flatten to implement it since the fact the outer iterator is always fused makes that bound seem pointless. I am sure this is just a massive brain fart on my part though.

Here's an example. The call to next_back is required because the backiter field needs to be populated first.

I think those bounds are just wrong (notice how in the example I require I: FusedIterator but the check still fails).

Edit: I'm opening an issue on the github repo

1 Like

Thank you so much! I apologize for my idiocy. Makes me feel slightly better that there appears to be bug with the non-sufficient requirement of having the outer iterator implement std::iter::FusedIterator. Should I—or you since you actually found it—raise a bug with the library team?

Edit: Just saw that you are opening an issue. Ignore my question above.

I've filed rust-lang/rust#81248

1 Like

I do not believe this line is correct in your bug filing: “I would expect the following code to either not compile (because iter doesn't implement FusedIterator )”. I think iter has the type std::vec::IntoIter, but it does implement std::iter::FusedIterator.

Edit: I meant to say that iter has the type std::iter::Flatten which does implement std::iter::FusedIterator when the iterator that was flattened does. The iterator that was flattened has the type std::vec::IntoIter which does implement std::iter::FusedIterator; thus that would make the type of iter also implement std::iter::FusedIterator.

The bug is that it shouldn't implement FusedIterator with just I: FusedIterator, because it doesn't actually behave in a fused manner unless U does too.

I know that is what the bug is; but in the bug filing, they said they expected the code should not even compile. That statement is not correct since the type does implement std::iter::FusedIterator—even though it should not. That is not a compilation bug. In other words, the filing should simply state that the fact the program causes a panic is proof that the std::iter::FusedIterator bound on the outer iterator is not enough for the type to also implement std::iter::FusedIterator. This is an implementation bug and not a compilation one.

As in, "I expect the constraints to be such that this code would be rejected at compile time."

1 Like

Ah! English can be vague at times. I (obviously) misinterpreted what they were saying. I mistakenly thought they were expecting the code to not compile as it stands now. Sorry @SkiFire13.

To be clear, I was thinking of 2 possibile situations:

  • If the implementation of FusedIterator for Flatten used the right bounds then my example code shouldn't compile because then iter wouldn't implement FusedIterator
  • If the implementation of FusedIterator for Flatten was correct then my example code wouldn't panic when ran because.

Yeah, it was just an interpretation issue. Your program is so trivial that we know the antecedents of both of your situations are false; so I was not thinking in the hypothetical sense (i.e., those situations are not relevant in our universe).

Update: PR rust-lang/rust#81306 has been merged

3 Likes