I want a function that takes an AbstractDict (it might be either Dict, an OrderedDict, etc.), and returns a dictionary of the same type, except for its parameters (the types of keys and values may differ). I fancied that this might be the way (toy example):
function dictoflengths(d::D{<:Any, <:AbstractVector}) where D
y = length.(values(d))
D(zip(keys(d), y))
end
But that’s not right, since when I define such function I get:
ERROR: TypeError: in Type{...} expression, expected UnionAll, got a value of type TypeVar
julia> function dictoflengths(d::D) where D<:AbstractDict{<:Any, <:AbstractVector}
y = length.(values(d))
D(zip(keys(d), y))
end
I guess you can’t split how many type parameters from the type (AbstractDict). Although I think semantically, the syntax where D<:AbstractDict could have worked.
I missed to add <:AbstractDict after where D in the function signature, but that doesn’t work yet. The function you suggest can be defined, but it doesn’t do what I want:
julia> function dictoflengths(d::D) where D<:AbstractDict{<:Any, <:AbstractVector}
y = length.(values(d))
D(zip(keys(d), y))
end
dictoflengths (generic function with 1 method)
julia> dictoflengths(OrderedDict(:a=>[1,2,3],:b=>[1,5]))
ERROR: MethodError: Cannot `convert` an object of type Int64 to an object of type Vector{Int64}
With that signature, D is a concrete type (OrderedDict{Symbol,Vector{Float64}}), whereas I wanted OrderedDict (a UnionAll).
I think I got it, after a bit of introspecting into data types:
get_rawtype(D::DataType) = getproperty(parentmodule(D), nameof(D))
function dictoflengths(d::D) where D<:AbstractDict{<:Any, <:AbstractVector}
T = get_rawtype(D)
y = length.(values(d))
T(zip(keys(d), y))
end
Any caveat about this going into the module that defines the UnionAll type to fetch it?