Regarding the example:
julia> v = [:a=>Float64, :n=>String]
2-element Array{Pair{Symbol,DataType},1}:
:a => Float64
:n => String
julia> a = [s=>Vector{T}() for (s, T) in v]
2-element Array{Pair{Symbol,B} where B,1}:
:a => Float64[]
:n => String[]
julia> eltype(a)
Pair{Symbol,B} where B
Shouldn't the compiler be able to pick up Pair{Symbol,Array{T,1} where {T}} instead of the generic Pair{Symbol,B} where B?
Because it would be a wrong result:
julia> Pair{Symbol, Vector{Int}} <: Pair{Symbol, Vector{T} where {T}}
false
julia> Pair{Symbol, Vector{Int}} <: Pair{Symbol, T} where {T}
true
Right, but surely it would be possible to infer it to Pair{Symbol, T} where T<:Vector?
Just to have that clear: the type is determined by promotion based on the actual values and has nothing to do with inference.
Correct, this type is not picked by the compiler, but by promote_typejoin. There are two possible strategies for promoting within a heterogeneous array:
promote_type) and convert all the elements to that type.Comprehensions use (1):
julia> [x for x in (1,1.0)]
2-element Array{Real,1}:
1
1.0
Array literals and concatenation (and lots of other things) use (2).
In general (1) is better, since it avoids converting (and therefore possibly copying) all the elements (in case they are e.g. arrays), and it also preserves more information since you're guaranteed to get out the exact values the comprehension expression generated. In any case, we're not changing this.
Most helpful comment
Just to have that clear: the type is determined by promotion based on the actual values and has nothing to do with inference.