rust-itertools / itertools

Extra iterator adaptors, iterator methods, free functions, and macros.
https://docs.rs/itertools/
Apache License 2.0
2.72k stars 309 forks source link

Feature request: .is_empty() #731

Closed ijackson closed 1 year ago

ijackson commented 1 year ago

I keep finding myself writing things like sometype.wombats().next().is_some(). (.count() is wrong because it walks the whole iterator; .any(|_| true) would be an alternative.

Maybe there should be .is_empty() or something? I'm not sure about the name. It would have to consume the iterator and since &mut I is an iterator, maybe it should have a name that more clearly implies that it eats something.

Philippe-Cholet commented 1 year ago

First, I'm no maintainer here. I think that the name is_empty implies it does not mutably change the iterator just like Vec::is_empty do not mutably change it. So next_is_none? Or nothing_next? I think next clearly suggest it consume one item.

fn some_name(&mut self) -> bool {
    self.next().is_none()
}

I'm not sure it is that important, and if not accepted, you can still do your own super-trait of Iterator.

LikeLakers2 commented 1 year ago

A couple of notes here:

First off, any iterator that implements FusedIterator is guaranteed to continue returning None after it returns None once (assuming the iterator isn't just implementing FusedIterator willy-nilly). From the docs:

Calling next on a fused iterator that has returned None once is guaranteed to return None again.

Second off, any iterator that implements ExactSizeIterator already has a method to determine if it's empty. Currently, ExactSizeIterator.is_empty() is behind a nightly feature - but you can just as easily use ExactSizeIterator.len() == 0.

I feel the above suggestion (a "is next item None?" method) may be a better inclusion, as it's something that can encompass iterators that don't know their size (or which may randomly return None).

jswrenn commented 1 year ago

I agree with @Philippe-Cholet here: An appropriate name for this method would be next_is_none. However, since that's a very trivial shorthand for .next().is_none(), I'm not really sure it's worth adding.

LikeLakers2 commented 1 year ago

@jswrenn Well, .next().is_none() would advance the iterator. Perhaps if next_is_none() could somehow peek at the next item without advancing the iterator, it'd be a nice addition?

Philippe-Cholet commented 1 year ago

Like Iterator::peekable? let it = it.peekable(); then it.peek().is_none(). There is also itertools::put_back but not really the same case.

jswrenn commented 1 year ago

In general, it's impossible to know whether an iterator is empty without advancing it.

ijackson commented 1 year ago

In general, it's impossible to know whether an iterator is empty without advancing it.

That's why I proposed that .is_empty() should consume it. But never mind, there is clearly too much opposition.

jswrenn commented 1 year ago

Does .next().is_none() satisfy your use-case?

ijackson commented 1 year ago

Does .next().is_none() satisfy your use-case?

Let me quote my initial message

I keep finding myself writing things like sometype.wombats().next().is_some(). [...]

Maybe there should be .is_empty() or something?

In other words: I find .next().is_some() reads oddly and is clumsy.