Imap (from IterTools.jl) doesn't preserve type

question

#1

Hello,

I don’t really know if that a bug or a limitation but imap from IterTools.jl doesn’t preserve type

julia> itr = imap(x->2*x, 1:10)
julia> collect(itr)
10-element Array{Any,1}:
  2
  4
  6
  8
 10
 12
 14
 16
 18
 20

I was expecting same result (ie Vector of Int) as

julia> 2*collect(1:10)
10-element Array{Int64,1}:
  2
  4
  6
  8
 10
 12
 14
 16
 18
 20

or

julia> map(x->2*x, 1:10)
10-element Array{Int64,1}:
  2
  4
  6
  8
 10
 12
 14
 16
 18
 20

My goal is to simply apply a function to values of an iterator and get a new iterator (preserving type)

Kind regards


#2

I think it is possible to define a type-stable iterator but it will need a special trick as Base.Generator does. Core.Inference.return_type can infer the return type as follows:

julia> Core.Inference.return_type(first, Tuple{typeof(2x for x in 1:10)})
Int64

I’m not a maintainer of IterTools.jl but it would be better to open an issue there.


#3

Thanks @bicycle1885 issue opened https://github.com/JuliaCollections/IterTools.jl/issues/15


#4

All that’s needed is to define iteratoreltype(::Type{<:IMap}) = EltypeUnknown()! collect is pretty good at figuring out what the container type should be.

The real issue is I hadn’t tagged a release yet :sheep:


#5

Thank you. I didn’t know that!


#6

collect also takes a type, so if you know the type T of the iterator (or if you want to collect to another type) you can do collect(T, iter)

julia> collect(Int, 1:2)
2-element Array{Int64,1}:
 1
 2

julia> collect(Complex{Float64}, 1:2)
2-element Array{Complex{Float64},1}:
 1.0 + 0.0im
 2.0 + 0.0im

#7

What is it that you can do with an imap that you cannot achieve with a generator?

julia> g = (2x for x in 1:10)
Base.Generator{UnitRange{Int64},##21#22}(#21, 1:10)

julia> collect(g)
10-element Array{Int64,1}:
  2
  4
  6
  8
 10
 12
 14
 16
 18
 20

Neither one seems to work with broadcasting, and otherwise they seem similar.