Say I have a type that satisfies the iterator interface. It’s a stateful iterator that behaves similarly to StatefulIterator
, so every time it generates an item the state changes internally.
What’s the right generic function to use to get the next item? StatefulIterator
uses popfirst!
, which seems reasonable, but then if I try to wrap my iterator in a generator the generator doesn’t implement popfirst!
:
MWE:
mutable struct MyIter
next::Int
max::Int
MyIter() = new(0, rand(1:10))
end
Base.IteratorSize(::Type{MyIter}) = Base.SizeUnknown()
Base.eltype(::MyIter) = Int
# internal function that gets the next item and mutates internal state
function getnext(m::MyIter)
if m.next > m.max
nothing
else
val = m.next
m.next += 1
val
end
end
function Base.iterate(m::MyIter, state=nothing)
next = getnext(m)
next === nothing ? nothing : (next, nothing)
end
# could this instead be implemented automatically by an iterator fallback?
Base.popfirst!(m::MyIter) = getnext(m)
m = MyIter()
# this works
popfirst!(m)
# this gives MethodError because `Base.Generator` doesn't have a `popfirst!` method
wrapper = (2x for x in m)
popfirst!(wrapper)
It feels like maybe I’m swimming upstream a little bit treating this stateful thing as an iterator, but the fact that StatefulIterator
exists makes me think this isn’t a totally crazy thing to do.
Would it make sense for there to be a popfirst!
fallback in terms of iterate
?