Motivation
I’m implementing a collect
-like function for a certain subtype of AbstractArray
, FixedSizeArray
(@giordano). The function is supposed to take an arbitrary iterator, consume it, and return a FixedSizeArray
value constructed from the iterator. While trying to do this, however, I realized I don’t understand anything about Base.IteratorElType
.
Base.IteratorElType
What goals is Base.IteratorElType
supposed to accomplish? What does it solve? What are its semantics in practice?
Empirically, the only place where I’ve found that Base.IteratorElType
matters is for collect
:
julia> it = Ref{Any}(7)
Base.RefValue{Any}(7)
julia> Base.IteratorEltype(it)
Base.HasEltype()
julia> collect(it)
0-dimensional Array{Any, 0}:
7
julia> map(identity, it)
0-dimensional Array{Int64, 0}:
7
julia> typeof(it)
Base.RefValue{Any}
julia> Base.IteratorEltype(::Type{Base.RefValue{Any}}) = Base.EltypeUnknown()
julia> Base.IteratorEltype(it)
Base.EltypeUnknown()
julia> collect(it)
0-dimensional Array{Int64, 0}:
7
julia> map(identity, it)
0-dimensional Array{Int64, 0}:
7
So Base.IteratorElType
affects the behavior of collect
, while it does not affect map
. The effect is that setting the return value to Base.EltypeUnknown()
makes collect
behave more like map
, otherwise it just preserves the element type exactly.
Is this really the only place where Base.IteratorElType
matters, for collect
? Is the current behavior even desirable? I guess returning Array{Int}
would actually be nicer than returning Array{Any}
?
Questions regarding the design of the new function
Basically I wonder if bothering with Base.IteratorElType
while implementing the new function is even necessary.
This is the interface I imagine so far:
"""
collect_as(t::Type{<:FixedSizeArray}, iterator)
Tries to construct a value of type `t` from the iterator `iterator`. The type `t`
must either be concrete, or a `UnionAll` without constraints.
"""
function collect_as(::Type{T}, iterator) where {T<:FixedSizeArray}
...
end
My intention is basically to have collect_as
behave like so:
-
If the element type is given, like, for example, in
collect_as(FixedSizeArray{Int}, iter)
, where the element type is given asInt
, the returned value must have the requested element type. SoBase.IteratorElType
doesn’t need to come into the picture. -
If no element type is requested, like, for example, in
collect_as(FixedSizeArray, iter)
, the intention is to ignoreBase.IteratorElType
, store the elements of the iterator into a temporaryFixedSizeArray
value whose element type iseltype(iter)
, then, at the end, returnmap(identity, temporary_fixed_size_array)
, so as to get a tight element type. So I’m ignoringBase.IteratorElType
, is that OK?