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?