Create Parameters object from a dictionary

I have two dictionaries:

d1 = Dict(:name => "Fido")
d2 = Dict(:name => "Spot", :breed => :poodle)

Which I’d like to use to create two

using Parameters
@with_kw mutable struct Dog
    name::String
    breed::Symbol = :husky
end

objects.

I presumed the splat operator would achieve this as it’s equivalent would in python, but this does not work

julia> Dog(d1...)
ERROR: MethodError: no method matching Dog(::Pair{Symbol, String})
Closest candidates are:
  Dog(::Any, ::Any) at ~/.julia/packages/Parameters/MK0O4/src/Parameters.jl:505
  Dog(; name, breed) at ~/.julia/packages/Parameters/MK0O4/src/Parameters.jl:493
  Dog(::Dog; kws...) at ~/.julia/packages/Parameters/MK0O4/src/Parameters.jl:569
  ...
Stacktrace:
 [1] top-level scope
   @ REPL[35]:1

julia> Dog(d2...)
ERROR: MethodError: Cannot `convert` an object of type Pair{Symbol, Any} to an object of type String
Closest candidates are:
  convert(::Type{String}, ::String) at essentials.jl:218
  convert(::Type{T}, ::T) where T<:AbstractString at strings/basic.jl:231
  convert(::Type{T}, ::AbstractString) where T<:AbstractString at strings/basic.jl:232
  ...
Stacktrace:
 [1] Dog(name::Pair{Symbol, Any}, breed::Pair{Symbol, Any})
   @ Main ~/.julia/packages/Parameters/MK0O4/src/Parameters.jl:505
 [2] top-level scope
   @ REPL[36]:1

How can I easily construct parameters objects from Dict?

If your dictionaries can be NamedTuples instead

julia> d1 = (; name = "Fido")
(name = "Fido",)

julia> d2 = (; name = "Spot", breed = :poodle)
(name = "Spot", breed = :poodle)

Then you can do

julia> Dog(; d1...)
Dog
  name: String "Fido"
  breed: Symbol husky

julia> Dog(; d2...)
Dog
  name: String "Spot"
  breed: Symbol poodle

Not without an explicit conversion which I’d rather avoid.

My data is stored in json files which I’m loading into dictionaries, I can get symbol keys using ()->DefaultDict{String,Any}(Missing). However, I’m unaware of how to get JSON.jl to return NamedTuple as opposed to dicts.

Loading .json dict data into a Parameters.jl struct would seem like a pretty common thing to do, so I presume I’m missing something. Pythons pydantic provides parse_file which loads a json file and instantiate the applicable object.

JSON3.jl is generally recommended over JSON.jl nowadays, and it supports both reading JSON into an existing type and creating types automatically based on the given JSON string.

1 Like
d = Dict([:name => "x"])
Dog(; d...)

Note the semicolon that makes d into keyword args. No need to convert the Dict to named tuples.

3 Likes

Oh dear, it was that easy. I didn’t realise you had to specify that you’re using kwargs, I presumed passing a kwarg implicitly meant use kwargs.