Construct object of type whose type is UnionAll

question

#1

The following does what I want

julia> (Dict{T,V} where {T,V})()
Dict{Any,Any} with 0 entries

It seems reasonable that this

julia> (Dict{T,Int} where T)()
ERROR: MethodError: no method matching Dict{T,Int64} where T()

should return Dict{Any,Int} with 0 entries. Even if there is a good reason why this is not so, what is the best way for me to construct an instance of Dict{Any,Int} from Dict{T,Int} where T ?


#2

(Dict{T,V} where {T,V})() is not normal type behavior, it’s a method defined specifically at https://github.com/JuliaLang/julia/blob/master/base/dict.jl#L126

But this works for any where type:

julia> t = Dict{T,Int} where T
Dict{T,Int64} where T

julia> t{Any}
Dict{Any,Int64}

julia> t{Any}()
Dict{Any,Int64} with 0 entries

#3

It looks like Dict() = Dict{Any,Any}() is a convenience function rather than a degenerate case of generic behavior.

I’d like to do this generically, for any UnionAll type. Or, something less ambitious, find a solution for my use case: Given a collection of concrete dictionary types, I want to construct a dictionary of the narrowest type that will accept all keys and values of instances of the dictionaries in the collection.

 julia> a = [Dict{Symbol,Int}, Dict{Symbol,Symbol}, Dict{Symbol,String}];

julia> T = reduce(typejoin,a)
Dict{Symbol,V} where V

julia> T()
ERROR: MethodError: no method matching Dict{Symbol,V} where V()

Defining T() generically might not be more widely useful. In that case a function, say construct(T) would do.

EDIT: I don’t mean strictly “narrowest”. I’d like to follow typejoin:

julia> typejoin(Dict{Symbol,Int}, Dict{Symbol,Float64})
Dict{Symbol,V} where V

#4

It sounds like you want to typejoin the key and value types, not the dict type itself.

julia> keytype(::Type{Dict{K,V}}) where {K,V} = K
keytype (generic function with 1 method)

julia> valtype(::Type{Dict{K,V}}) where {K,V} = V
valtype (generic function with 1 method)

julia> a = [Dict{Symbol,Int}, Dict{Symbol,Symbol}, Dict{Symbol,String}]
3-element Array{DataType,1}:
 Dict{Symbol,Int64} 
 Dict{Symbol,Symbol}
 Dict{Symbol,String}

julia> t = Dict{reduce(typejoin, map(keytype, a)), reduce(typejoin, map(valtype, a))} 
Dict{Symbol,Any}

julia> t()
Dict{Symbol,Any} with 0 entries

#5

This gets me part of the way there. But, this gives

julia> a = [Dict{Symbol,Int}, Dict{Symbol,Float64}];

julia> t = Dict{mapreduce(keytype,typejoin,a), mapreduce(valtype,typejoin,a)}
Dict{Symbol,Real}

whereas

julia> typejoin(Dict{Symbol,Int}, Dict{Symbol,Float64})
Dict{Symbol,V} where V

I’ll think about how much generality I really need and post again.


#6

I think your solution plus isconcretetype (isleaftype) is enough. Thanks.

EDIT: I mean any type that is not concrete can be replaced with Any.