-
Notifications
You must be signed in to change notification settings - Fork 310
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement DoubleEndedIterator and FusedIterator for ZipEq. #531
base: master
Are you sure you want to change the base?
Conversation
I also noticed we're missing custom implementations of |
I think there's an important semantic question about what Notably, with this change, going forward or backwards give different elements if the inputs have different lengths. And if iteration stops early for some reason -- Is that ok? I don't know. What should happen here? I don't know that either. |
As a thought: Maybe it could make sense to do a check like this? let (hint1, hint2) = (a.size_hint(), b.size_hint());
assert!(hint1.0 <= hint2.1.unwrap_or(usize::MAX) && hint2.0 <= hint1.1.unwrap_or(usize::MAX); That would at least catch the easy cases early, without changing the trait requirements. |
I think it'd be fine if this PR resolved that issue by bounding the
#[cfg(test)]
use itertools::zip_eq;
#[test]
#[should_panic]
fn test() {
let short = 0..1;
let long = 0..9;
let iter = zip_eq(short, long); // no panic :(
} That's neat. I was aware of the behavior, but it hadn't noticed how odd it was that the documentation implied that Here's a thought:
|
That's not perfectly analogous, since different lengths are acceptable with So it would feel kinda weird to me to have the forward direction here panic lazily but the backward direction panic eagerly.
In a way, this is what my size_hint check is doing, just in the same method -- if you pass two ESIs, it'll panic immediately. But it'll also panic immediately for So it might be ok to just carefully document "⚠ This may do weird (but safe) things if you pass non-equal-length iterators ⚠" and treat it as "garbage in garbage out" in those cases. |
Ah, yeah.
I think I'm sold on this approach, but I wish I knew more about how people were using |
Yeah, would be nice to know whether things are ESI in practice. 👍 to following rayon. The more code can flip back and forth between serial and parallel the better. I guess it could just change to ESI and early panic in a major version bump and see who complains 😆 |
I once stumbled upon a similar issue, and PR'd Not sure, though, if that applies to |
Fascinating! Given that, I don't have any objections to merging this PR. The issue of a panicking |
I'm not so sure about this PR any more, some important issues were raised. I didn't even think of the different-size-different-elements problem, because it doesn't really matter for my use cases.
Edit: I missed @phimuemue's comment, so technically it's fine. To give some perspective, I'm kind of confused why the default version of zip is the one that silently ignores differently sized iterators. I grepped a few of my projects in In that light it doesn't really matter for me whether the assert happens at the start or the end, but of course the start is preferable. I really like the It could be interesting to grep crates that use |
Okay I looked around a bit on GitHub, this search query is the best I could come up with: It looks like most uses are with Another interesting datapoint is that |
550: Add More FusedIterator r=jswrenn a=aobatact These Iterator is fused if the underlying Iterator is fused. - `FilterOk` - `FilterMapOk` - `InterleaveShortest` - `KMergeBy` - `MergeBy` - `PadUsing` - `Positions` - `Product` - `RcIter` - `TupleWindows` - `Unique` - `UniqueBy` - `Update` - `WhileSome` These is fused even though the underlying Iterator is not fused. - `Combinations` - `CombinationsWithReplacement` - `Powerset` - `RepeatN` - `WithPosition` `FusedIterator` can be added to these structs. Related #55, #152, #531, #533 I separate the pull request with #548 because these Iterator are sure to be fused because it was documented, but I'm not 100% sure that the structs in this PR is actually fused. (Though I believe it is.) Co-authored-by: aobatact <[email protected]>
I wanted to use
zip_eq(..).rev()
and that required aDoubleEndedIterator
implementation, so I added one. I checked the other "marker" traits and it was pretty easy to add aFusedIterator
impl as well. The generic trait bounds are a bit too strong now, technically we don't need both of the inner iterators to be aFusedIterator
, but I don't think we can do better in the current rust version.I didn't create an issue for this since it's such a small change, I hope that's okay.