Instantiate the type from a few strings

question

#1

I have a Dict{String, <values>} and I want to instantiate a type depending on the keys of that dict:

x = Dict("a" => 2, "b" => 0.0)
struct AnB
   a::Int 
   b::Float64
end
y = fun(x) # returns AnB(2, 0.0)

I’m going to have groups of dicts where each group has the exact same keys. I’ll make sure that there is always a type defined with the correct fields for each group of dicts. But how do I write this fun function so it’ll accept any of the possible dicts?

P.S.
If it helps, I’ll add that the type of the keys of the dicts doesn’t have to be String, but instead can be Symbol.


#2
julia> using Parameters

julia> @with_kw struct AnB
          a::Int
          b::Float64
       end
AnB

julia> x
Dict{String,Any} with 2 entries:
  "b" => 0.0
  "a" => 2

julia> AnB(; (Symbol(k) => v for (k, v) in x)...)
AnB
  a: Int64 2
  b: Float64 0.0

julia> x = Dict(:a => 2, :b => 0.0) # Symbols
Dict{Symbol,Any} with 2 entries:
  :a => 2
  :b => 0.0

julia> b = AnB(; x...)
AnB
  a: Int64 2
  b: Float64 0.0

#3

Thanks! I started tinkering with hashing the concatenation of the keys and using Type{Val{<hash>}}… Awesome that this is already solved.


#4

Assuming that the type is somehow selected based on the keys, here is an example with symbols:

# define a method like below for each type
instantiate(dict::Dict{Symbol, <: Any}) =
    instantiate(Val(tuple(keys(dict)...)), values(dict)...)

struct AnB
   a::Int
   b::Float64
end

# you can automate this step with a macro on the struct
instantiate(::Val{(:a, :b)}, a, b) = AnB(a, b)

instantiate(Dict(:a => 2, :b => 0.0)) # AnB(2, 0.0)

BTW, this problem may be a very good match for named tuples.


#5

Nice!