Currently, the syntax a => b creates the narrowest typed-Pair for a and b. However, when this pair is being used to construct a heterogeneous Dict, this isn't exactly what you want: you'd prefer the pairs to be created from the outset with the Dict's key and value type:
julia> f() = Dict{Symbol,Any}(:a => 1, :b => "hello")
f (generic function with 1 method)
julia> code_typed(f, ())
1-element Vector{Any}:
CodeInfo(
1 โ %1 = %new(Pair{Symbol,Int64}, :a, 1)::Pair{Symbol,Int64}
โ %2 = %new(Pair{Symbol,String}, :b, "hello")::Pair{Symbol,String}
โ %3 = invoke Dict{Symbol,Any}(%1::Pair{Symbol,Int64}, %2::Vararg{Pair,N} where N)::Dict{Symbol,Any}
โโโ return %3
) => Dict{Symbol,Any}
julia> @btime f()
195.619 ns (6 allocations: 672 bytes)
Dict{Symbol,Any} with 2 entries:
:a => 1
:b => "hello"
is not as nice (in terms of generated code) as
julia> ft() = Dict{Symbol,Any}(Pair{Symbol,Any}(:a, 1), Pair{Symbol,Any}(:b, "hello"))
ft (generic function with 1 method)
julia> code_typed(ft, ())
1-element Vector{Any}:
CodeInfo(
1 โ %1 = %new(Pair{Symbol,Any}, :a, 1)::Pair{Symbol,Any}
โ %2 = %new(Pair{Symbol,Any}, :b, "hello")::Pair{Symbol,Any}
โ %3 = invoke Dict{Symbol,Any}(%1::Pair{Symbol,Any}, %2::Vararg{Pair{Symbol,Any},N} where N)::Dict{Symbol,Any}
โโโ return %3
) => Dict{Symbol,Any}
julia> @btime ft()
135.983 ns (6 allocations: 672 bytes)
Dict{Symbol,Any} with 2 entries:
:a => 1
:b => "hello"
We could have a @Dict that performs this operation, but before implementing this, is there any chance this is something that should just be done by the parser?
An alternative might be explicitly converting the pairs in the Dict constructor like this:
julia> struct Dict2{K,V}
Dict2{K,V}(x::Pair...) where {K,V} = Dict{K,V}(map(p -> convert(Pair{K,V}, p), x)::Tuple{Vararg{Pair{K,V}}}...)
end
julia> code_typed(f2, ())
1-element Vector{Any}:
CodeInfo(
1 โ %1 = %new(Pair{Symbol,Any}, :a, 1)::Pair{Symbol,Any}
โ %2 = %new(Pair{Symbol,Any}, :b, "hello")::Pair{Symbol,Any}
โ %3 = invoke Dict{Symbol,Any}(%1::Pair{Symbol,Any}, %2::Vararg{Pair{Symbol,Any},N} where N)::Dict{Symbol,Any}
โโโ return %3
) => Dict{Symbol,Any}
julia> @btime f()
216.752 ns (6 allocations: 672 bytes)
Dict{Symbol,Any} with 2 entries:
:a => 1
:b => "hello"
julia> @btime ft()
165.954 ns (6 allocations: 672 bytes)
Dict{Symbol,Any} with 2 entries:
:a => 1
:b => "hello"
julia> @btime f2()
159.693 ns (6 allocations: 672 bytes)
Dict{Symbol,Any} with 2 entries:
:a => 1
:b => "hello"
Although I don't know whether that would still be as fast if the pairs are not just constants.
is there any chance this is something that should just be done by the parser
No :smile:
Most helpful comment
An alternative might be explicitly converting the pairs in the
Dictconstructor like this:Although I don't know whether that would still be as fast if the pairs are not just constants.