length(Iterators.flatten(...)) not working

using julia 1.1.0 the example taken from the documentation Iteration utilities · The Julia Language works, however while collect works, length throughs an error

julia> collect(Iterators.flatten((1:2, 8:9)))
4-element Array{Int64,1}:
 1
 2
 8
 9

julia> length(Iterators.flatten((1:2, 8:9)))
ERROR: ArgumentError: Iterates of the argument to Flatten are not known to have constant length
Stacktrace:
 [1] flatten_length(::Base.Iterators.Flatten{Tuple{UnitRange{Int64},UnitRange{Int64}}}, ::Type) at .\iterators.jl:892
 [2] length(::Base.Iterators.Flatten{Tuple{UnitRange{Int64},UnitRange{Int64}}}) at .\iterators.jl:894
 [3] top-level scope at none:0

I guess this is a bug, isn’t it?

adding

Base.length(f::Base.Iterators.Flatten{<:NTuple{N, Any}}) where N = sum(length, f.it)

fixes this for me, but maybe it is better to use generated function here?

or even more general fallback

Base.length(f::Iterators.Flatten) = sum(length, f.it)

I would actually go with this one, is there a reason this is not in Base.Iterators already?

1 Like

Not sure, probably just an oversight. I would open an issue or a PR about adding it.

1 Like

good to hear, can you point me to where to open the issue/PR? thanks a lot!

3 Likes

Not all Flatten iterators should have their length known,
only if all the iterators being flattened have known length does the overall have known length.

But in your example, that is indeed the case so it should work.

Here is the code from te old version of IterTools for chain, which has now been replaced by flatten in Base.

The question is whether we want length defined when it’s not O(1). See for example this PR which very conservatively added length for a couple of cases where the element type of the flattened iterator are known statically.

For your example of a tuple of ranges, I would say it’s fine to add length as tuples are never too long in practice, but for e.g. Vector{<:Range}, I don’t know. For example we have BitSet with O(n) length, so why not iterators?