Retrieve the type of `AbstractDict` (without parameters) from a concrete dictionary type

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

How could I do what I want? Thanks!


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?

if you’re not using the type parameter of D, I guess you don’t need the {}