-
-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
Add precision about stateful iterators to isempty
#43900
Conversation
The manual now mentions that stateful iterators should implement `isdone`, so it appears `isempty` is not supposed to consume elements. This matters a lot for callers as if you can't rely on this you can't do `isempty(c) && return; for x in c` but instead have to call `iterate(c)` manually.
Anybody willing to review this? |
I think the docstring is correct depending on what you exactly mean by "guaranteed." For example, julia> ch = foldl(push!, 1:3; init = Channel{Int}(Inf))
Channel{Int64}(9223372036854775807) (3 items available)
julia> close(ch)
julia> itr1 = (x + 1 for x in ch);
julia> isempty(itr1)
false
julia> collect(itr1)
2-element Vector{Int64}:
3
4 i.e., an iterator transform wrapping a stateful iterator still mutates the stateful iterator. It is fixable by forwarding Another tricky example is that user-defined function is not pure: julia> COUNTER = 3
itr2 = Iterators.takewhile(1:3) do _
global COUNTER
(COUNTER -= 1) > 0
end;
julia> collect(itr2)
2-element Vector{Int64}:
1
2
julia> COUNTER = 3
itr2 = Iterators.takewhile(1:3) do _
global COUNTER
(COUNTER -= 1) > 0
end;
julia> isempty(itr2)
false
julia> collect(itr2)
1-element Vector{Int64}:
1 I think we can put "guaranteed" in the docstring by declaring sufficiently many things as undefined behavior (i.e., violation of precondition is not detected). That said, I think the "look before you leap" approach of using |
Those are some of the literal defining examples of why we just have |
So maybe we should rather say that calling The difficulty is that Cc: @cmcaine |
I don't think the docstring should say that this is a guarantee because there are too many iterables that break the guarantee. I think we should instead give a warning, something like this:
It's true that the general approach of |
And maybe we should fix |
And Base.Generator should forward the isdone method, too. It can't help for Generators with a guard: The idea of my extra |
Yes, otherwise we need to remove |
It is permitted to throw, if it is non-computable, or just return |
What is the Edit: I was imagining that |
When |
Hmm. That's not how function isempty(itr)
d = isdone(itr)
d !== missing && return d
iterate(itr) === nothing
end Here an iterable of indeterminate done-ness is declared empty. If function isempty(itr)
d = isdone(itr)
d === true && return d
iterate(itr) === nothing
end And the docs for
|
That does not fix the stated problem, but makes it worse. When something is mutable, you cannot know if someone else mutates it, so you cannot know if it becomes empty after you checked. |
I will note though that if you come across a case where a mutable iterator changes here, that should be fixed by adding an |
The manual now mentions that stateful iterators should implement `isdone`, so it appears `isempty` is not supposed to consume elements. This matters a lot for callers as if you can't rely on this you can't do `isempty(c) && return; for x in c` but instead have to call `iterate(c)` manually.
The manual now (#43099) mentions that stateful iterators should implement
isdone
, so it appearsisempty
is not supposed to consume elements.This matters a lot for callers as if you can't rely on this you can't do
isempty(c) && return; for x in c
but instead have to calliterate(c)
manually.Maybe the "should" in the manual and the docstring should be "must" instead?