Just curious, how is the container type determined for map
?
It seem pretty magical to me:
julia> @code_warntype map(x -> x/2, rand(Int, 5))
Body::Array{Float64,1}
1995 1 ─ %1 = %new(Base.Generator{Array{Int64,1},getfield(Main, Symbol("##3#4"))}, getfield(Main, Symbol("##3#4"))(), A)::Base.Generator{Array{Int64,1},getfield(Main, Symbol("##3#4"))} │╻╷ Type
│ %2 = invoke Base._collect(_3::Array{Int64,1}, %1::Base.Generator{Array{Int64,1},getfield(Main, Symbol("##3#4"))}, $(QuoteNode(Base.EltypeUnknown()))::Base.EltypeUnknown, $(QuoteNode(Base.HasShape{1}()))::Base.HasShape{1})::Array{Float64,1}
└── return %2
I guess it boils down to this: how is the output type of functions determined before they are evaluated in regular Julia? I understand that this is definitely something that the compiler should be able to figure out, but how would I be able to write a function that uses the compiler’s smarts to pre-allocate an output array?
It isn’t. The inference type is used for the empty case.
Don’t. Not for any non-empty case or at least not without making sure your code runs just fine without it.
1 Like
Good advice to keep it simple, but it looks like the inference type is used by map. I’m just curious how it works.
julia> @code_warntype map(x -> x/2, rand(Int, 0))
Body::Array{Float64,1}
1995 1 ─ %1 = %new(Base.Generator{Array{Int64,1},getfield(Main, Symbol("##5#6"))}, getfield(Main, Symbol("##5#6"))(), A)::Base.Generator{Array{Int64,1},getfield(Main, Symbol("##5#6"))} │╻╷ Type
│ %2 = invoke Base._collect(_3::Array{Int64,1}, %1::Base.Generator{Array{Int64,1},getfield(Main, Symbol("##5#6"))}, $(QuoteNode(Base.EltypeUnknown()))::Base.EltypeUnknown, $(QuoteNode(Base.HasShape{1}()))::Base.HasShape{1})::Array{Float64,1}
└── return %2
oh nevermind, I guess the code_warntype
basically says how it’s done.
BTW, with union splitting, I wonder if this is still needed. map
& friends could just return Any[]
for empty collections.