Skip to content

Refine eltype(::Type{<:Flatten})#48276

Closed
jakobnissen wants to merge 1 commit intoJuliaLang:masterfrom
jakobnissen:flateltype
Closed

Refine eltype(::Type{<:Flatten})#48276
jakobnissen wants to merge 1 commit intoJuliaLang:masterfrom
jakobnissen:flateltype

Conversation

@jakobnissen
Copy link
Copy Markdown
Member

@jakobnissen jakobnissen commented Jan 14, 2023

The new approach uses typejoin over eltype of all the underlying iterators of the Flatten. This way, eltype(flatten(((1,), [1]))) == Int, whereas it was Any before, due to the heterogenous underlying iterators.

Closes #48249

The new approach uses `typejoin` over `eltype` of all the underlying iterators
of the `Flatten`. This way, `eltype(flatten(((1,), [1]))) == Int`, whereas it
was `Any` before, due to the heterogenous underlying iterators.
Comment on lines +1170 to +1174
tuple_eltype_join(::Type{Tuple{T}}) where T = eltype(T)
function tuple_eltype_join(::Type{T}) where {T <: Tuple}
E = eltype(Base.tuple_type_head(T))
E === Any ? Any : typejoin(E, tuple_eltype_join(Base.tuple_type_tail(T)))
end
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
tuple_eltype_join(::Type{Tuple{T}}) where T = eltype(T)
function tuple_eltype_join(::Type{T}) where {T <: Tuple}
E = eltype(Base.tuple_type_head(T))
E === Any ? Any : typejoin(E, tuple_eltype_join(Base.tuple_type_tail(T)))
end
tuple_eltype_join(::Type{T}) where {T <: Tuple} = Base.typejoin(eltype.(fieldtypes(T))...)

Does the above also work, or are there reasons to use the recursive implementation? I suppose the recursive implementation might terminate faster if the typejoin becomes Any?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Superceded by next suggestion)

Comment on lines +1168 to +1174
eltype(::Type{Base.Iterators.Flatten{T}}) where T = tuple_eltype_join(T)

tuple_eltype_join(::Type{Tuple{T}}) where T = eltype(T)
function tuple_eltype_join(::Type{T}) where {T <: Tuple}
E = eltype(Base.tuple_type_head(T))
E === Any ? Any : typejoin(E, tuple_eltype_join(Base.tuple_type_tail(T)))
end
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eltype(::Type{Zip{Is}}) where {Is<:Tuple} = Tuple{map(eltype, fieldtypes(Is))...}
also takes the splatting approach. If this works, maybe we could then just inline the whole thing, like this?

Suggested change
eltype(::Type{Base.Iterators.Flatten{T}}) where T = tuple_eltype_join(T)
tuple_eltype_join(::Type{Tuple{T}}) where T = eltype(T)
function tuple_eltype_join(::Type{T}) where {T <: Tuple}
E = eltype(Base.tuple_type_head(T))
E === Any ? Any : typejoin(E, tuple_eltype_join(Base.tuple_type_tail(T)))
end
eltype(::Type{Base.Iterators.Flatten{T}}) where T = Base.typejoin(map(eltype, fieldtypes(T))...)

@gaurav-arya
Copy link
Copy Markdown
Contributor

gaurav-arya commented Jan 14, 2023

Also, in any case, we still need to handle the case where the flatten is taken over a non-tuple:

julia> iter = Iterators.flatten([(1,), [3,4,5]])
julia> eltype(typeof(iter))
ERROR: MethodError: no method matching tuple_eltype_join(::Type{Vector{Any}})

It might also be nice to fix the HasIteratorEltype trait:

julia> iter = Iterators.flatten(((1,), [2]))
Base.Iterators.Flatten{Tuple{Tuple{Int64}, Vector{Int64}}}(((1,), [2]))

julia> eltype(iter)
Int64

julia> Base.IteratorEltype(iter)
Base.EltypeUnknown()

Assuming these are valid issues, happy to take a stab at patching them.

@jakobnissen
Copy link
Copy Markdown
Member Author

Closing in favor of #48277

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

eltype could be more accurate for Iterators.flatten

2 participants