Generator - iterators should deliver accurate eltype


#1

The following snippet of code unexpectedly returns Any and not Int64 from eltype:

julia> g = (x for x in 1:5)
Base.Generator{UnitRange{Int64},##1#2}(#1, 1:5)
julia> eltype(g)
Any

Reason seems that Base.Generator does not support eltype nor Base.iteratoreltype.

I want to propose the following additions to generator.jl to fix that.

Base.iteratoreltype(g::Base.Generator{I,F}) where {I,F} = Base.iteratoreltype(g.iter)
Base.eltype(g::Base.Generator{I,F}) where {I,F} = promote_type(Base.return_types(g.f, (eltype(g.iter),))...)
Base.eltype(g::Base.Generator{I,typeof(identity)}) where I = eltype(g.iter) # won't work for example

After that I receive:

julia> g = (x for x in 1:5 if x != 3);

julia> h = (x for x in 0.5:0.1:11.0)
Base.Generator{StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},##31#32}(#31, 0.5:0.1:11.0)
julia> i = (exp(x) for x in -1:2:10)
Base.Generator{StepRange{Int64,Int64},Base.#exp}(exp, -1:2:9)
julia> eltype(g)
Int64
julia> eltype(h)
Float64
julia> eltype(i)
Float64

All fineā€¦ I propose to discuss the addition of the 3 lines of code.


#2

might try submitting a PR on github


#3

See e.g. https://github.com/JuliaLang/julia/issues/18695 and links therein.


#4

@stevengj I see, that the problem is not new, but has not been solved, because there is no general solution, or for other reasons, I could not recognize in the referred text.
But if the Generator delivers an element type, we should use that, I think. If not, we could throw an appropriate exception.
In my proposal, the eltype of g::Generator is delegated to eltype(g.f), which also works recursively, as the examples show.
The third line does not work, because for g = (x for x in ...), the compiler does not generate g.f == identity, as I had assumed.
In the second line, promote_type(Base.return_types(g.f, (eltype(g.iter),))...) could probably replaced by Core.Inference.return_type(g.f, (eltype(g.iter),)).