`iterate` returning iter, next-state and iter's original length

I am using a custom iterator that delegates into a struct to obtain the iterative grist, say a vector. I think it is appropriate to check if the current state (like an index) exceeds the length of the delegatee.

I do not want to recalculate the vector’s length at each iteration, and keeping the length in the struct does not work for external reasons.

What is an appropriate way to define iterate so that the next state returned is a tuple (total_length, next_index) and have it all work? I would prefer that the state stay simple (a two tuple) rather than embed both in a struct.

struct Foo{T <: AbstractVector} # type for MWE
    v::T
end

function Base.length(c::Foo)
    @info "length was called, and it was darn expensive"
    length(c.v)
end

function Base.iterate(c::Foo)
    len = length(c)
    len > 0 || return nothing
    (c.v[1], (2, len))
end

Base.iterate(c::Foo, (i, len)) = i > len ? nothing : (c.v[i], (i+1, len))

then

julia> foreach(println, Foo(1:10))
[ Info: length was called, and it was darn expensive
1
2
3
4
5
6
7
8
9
10

But that said, I would just define a wrapper type that caches the length.

Doesn’t a vector know its length?

strings do not know their length
although I am not using strings here

You may have resolved this as Julia does, often – problem? no, its no problem.

The length I need is several layers deep into substructure while iterating on x length(x.partsofx.vecparts.bluevec). I don’t believe the levels of dot indirection are very costly – I do believe they are not ameanable to compile time prelocation.

thanks for that … I was looking for (c, (i, len))

I’ll benchmark both approaches.