# Construct an immutable type from a Dict

**URL:** <https://discourse.julialang.org/t/construct-an-immutable-type-from-a-dict/26709>\
**Category:** Internals & Design\
**Tags:** question\
**Created:** [July 23, 2019, 10:52pm UTC](https://discourse.julialang.org/t/construct-an-immutable-type-from-a-dict/26709 "2019-07-23T22:52:53Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![singularitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/singularitti/32/17678_2.png) [@singularitti](https://discourse.julialang.org/u/singularitti)\
**Post date:** [July 23, 2019, 10:52pm UTC](https://discourse.julialang.org/t/construct-an-immutable-type-from-a-dict/26709/1 "2019-07-23T22:52:53Z")

</div>

In development, I sometimes have an immutable type (for some reason, I do not want it to be mutable) with a large number of fields (5 in the following example), like

```julia
struct A
   mass::Int
   velocity::String
   coordinate::Vector
   time::Tuple
   frequency::Float64
end

```

Please do not consider this question as a physics problem, the fieldnames I used here are just to say they can be long enough that we need a `Dict` to “remember” them.  
Now suppose I have a `Dict` of fields (read from a file, for example),

```julia
Dict(
    :mass => 1,
    :velocity => "2.0",
    :coordinate => [3, 3, 3],
    :time => (2, 3),
    :frequency => 5.0
)

```

How can I construct an `A` type from the `Dict`?

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [July 23, 2019, 11:43pm UTC](https://discourse.julialang.org/t/construct-an-immutable-type-from-a-dict/26709/2 "2019-07-23T23:43:54Z")

</div>

Something in your explanation doesn’t really fit with other parts…

> [@singularitti](#):
>
> the fieldnames I used here are just to say they can be long enough that we need a `Dict` to “remember” them.

Why is that? For one, since computer doesn’t really care about the length of the field name I assume this is to help a human (user or developer) to remember them. The computer only care about the length regarding memory consumption and a `Dict` certainly doesn’t help in that regard. Moreover, I don’t think a `Dict` can really help you remember it either. Are you creating them, in which case you have to type the field names. Or are you getting it from somewhere, in which case the reader code should have no problem remembering the field names and you shouldn’t have to put them into a `Dict` to “remember them”.

> [@singularitti](#):
>
> read from a file, for example

So if you are reading from a file, I still don’t really see how `Dict` is essential here. The `Dict` is at most a slightly different representation of what you get from the file so are you just saying that you are using a `Dict` as a generic intermediate format to store the info that you later want to put into your type? Depending on the design, you could be better off not have this step but having this is certainly a valid choice. Is that what you want? (Even if this is the case I still don’t really see how it helps you remember though, especially since there isn’t really any alternative that does require you to remember the field names…)

What I said above doesn’t really affect the way you construct `A` but it’ll strongly affect whether you even need to do these and how do you integrate the code if you do need it.

Now onto creating `A`. The only way you can create an immutable type is from it’s constructor so if you want to make any generic code you must make some assumptions about the constructor. The only one you can make without special convention in your own code is to assume it has something similar to the default constructor, in which case the only way to do what you want is pretty much `A(d[:mass], d[:velocity], d[:coordinate], d[:time], d[:frequency])` and variances using `get` etc to handle missing/default values. You can get the effect of the expression above in many different ways. If this is something that is type stable (i.e. the caller know the type) you can use generated function and generate the expression above based on the input type, sth like this,

```julia
julia> :(A($((:(d[$(QuoteNode(f))]) for f in fieldnames(A))...)))
:(A(d[:mass], d[:velocity], d[:coordinate], d[:time], d[:frequency]))

```

if this is sth like deserialization where the caller doesn’t really know the type (the type is also read from the file, for example) then you can just construct the arguments directly, sth like,

```julia
julia> A((d[f] for f in fieldnames(A))...)
A(1, "2.0", [3, 3, 3], (2, 3), 5.0)

```

which one to pick is strongly depending on what you are doing, as mentioned above.

P.S. many of your field types for `A` are not concrete types and you may want to change that.

---

<div class="post-metadata">

**Author:** ![singularitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/singularitti/32/17678_2.png) [@singularitti](https://discourse.julialang.org/u/singularitti)\
**Post date:** [July 24, 2019, 2:17am UTC](https://discourse.julialang.org/t/construct-an-immutable-type-from-a-dict/26709/3 "2019-07-24T02:17:33Z")

</div>

Hi @yuyichao, thank you for your great help! I should have clarified on what I want more detailedly. The example I set is just an [MWE](https://en.wikipedia.org/wiki/Minimal_working_example?oldformat=true), so it might not represent my use case precisely, which confuses.

> [@yuyichao](#):
>
> Why is that? For one, since computer doesn’t really care about the length of the field name I assume this is to help a human (user or developer) to remember them.

Indeed, it was intended to help human “remember”, like what a namedtuple is to a tuple.

> [@yuyichao](#):
>
> Or are you getting it from somewhere, in which case the reader code should have no problem remembering the field names and you shouldn’t have to put them into a `Dict` to “remember them”.

Yes, I read a [Fortran namelist](http://jules-lsm.github.io/vn4.1/namelists/intro.html), which looks like a dictionary. And I have several types representing those namelists, some of them could have a hundred fields, which you definitely do not want to create from scratch but from a template, and modify some fields each time creating one. That uses a `Dict`. Check my [code](https://github.com/MineralsCloud/QuantumESPRESSO.jl/blob/master/src/Namelists/PW.jl) if you are interested.

> [@yuyichao](#):
>
> are you just saying that you are using a `Dict` as a generic intermediate format to store the info that you later want to put into your type?

Kind of. I want to create one from my template, and `merge` the fields with my `Dict`’s entries to create a new `Namelist`.

> [@yuyichao](#):
>
> ```julia
> julia> :(A($((:(d[$(QuoteNode(f))]) for f in fieldnames(A))...)))
> :(A(d[:mass], d[:velocity], d[:coordinate], d[:time], d[:frequency]))
> 
> ```

I have thought about using a macro. I tried several times but failed. Thank you for your solution.

> [@yuyichao](#):
>
> ```julia
> julia> A((d[f] for f in fieldnames(A))...) 
> A(1, "2.0", [3, 3, 3], (2, 3), 5.0)
> 
> ```

It’s a shame that I did not come up with a generator. My focus was on how to make a macro. Thank you!

> [@yuyichao](#):
>
> P.S. many of your field types for `A` are not concrete types and you may want to change that.

I am aware of that, it is just an example. 🙂

---

<div class="post-metadata">

**Author:** ![mauro3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mauro3/32/292_2.png) [@mauro3](https://discourse.julialang.org/u/mauro3)\
**Post date:** [July 24, 2019, 6:43am UTC](https://discourse.julialang.org/t/construct-an-immutable-type-from-a-dict/26709/4 "2019-07-24T06:43:18Z")

</div>

I think you may want to look for something like `Base.@kwdef` or, if you need more functionality (unpacking, conversion to/from Dict), look at [https://github.com/mauro3/Parameters.jl](https://github.com/mauro3/Parameters.jl).

---

<div class="post-metadata">

**Author:** ![singularitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/singularitti/32/17678_2.png) [@singularitti](https://discourse.julialang.org/u/singularitti)\
**Post date:** [July 24, 2019, 6:51am UTC](https://discourse.julialang.org/t/construct-an-immutable-type-from-a-dict/26709/5 "2019-07-24T06:51:38Z")

</div>

Thanks, actually I [am using Parameters.jl](https://github.com/MineralsCloud/QuantumESPRESSO.jl/blob/master/src/Namelists/PW.jl). But it [cannot construct](https://mauro3.github.io/Parameters.jl/latest/api/) a type from a `Dict` directly, it needs an instance of that type first.

```julia
MM(m::MM; kws...) = reconstruct(mm,kws)
MM(m::MM, di::Union{AbstractDict, Tuple{Symbol,Any}}) = reconstruct(mm, di)

```

Therefore, if I want to create an instance from a `Dict`, I need to construct an instance first by giving it some random parameters. However, I always have trouble determining what values should be given.

---

<div class="post-metadata">

**Author:** ![mauro3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mauro3/32/292_2.png) [@mauro3](https://discourse.julialang.org/u/mauro3)\
**Post date:** [July 24, 2019, 7:26am UTC](https://discourse.julialang.org/t/construct-an-immutable-type-from-a-dict/26709/6 "2019-07-24T07:26:46Z")

</div>

This works:

```julia
julia> using Parameters

julia> @with_kw struct A
       a
       b
       end
A

julia> A(;Dict(:a=>1, :b=>3)...)
A
  a: Int64 1
  b: Int64 3

```

Does this cover your use-case?

---

<div class="post-metadata">

**Author:** ![singularitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/singularitti/32/17678_2.png) [@singularitti](https://discourse.julialang.org/u/singularitti)\
**Post date:** [July 24, 2019, 7:37am UTC](https://discourse.julialang.org/t/construct-an-immutable-type-from-a-dict/26709/7 "2019-07-24T07:37:52Z")

</div>

Right. It covers. I was not thinking of unzipping a generator or a `Dict`. I forgot there was a method

```julia
MM(;r=1000,a=error("no default for a")) = MM(r,a) # outer kw, so no type-paras are needed when calling

```

Thank you for all of your help! @mauro3 @yuyichao

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [July 25, 2019, 12:25pm UTC](https://discourse.julialang.org/t/construct-an-immutable-type-from-a-dict/26709/8 "2019-07-25T12:25:33Z")

</div>

If the Dict is mapping symbols to values, you can simply do array comprehensions:

```julia
julia> struct A
          mass::Int
          velocity::String
          coordinate::Vector
          time::Tuple
          frequency::Float64
       end

julia> d = Dict(
           :mass => 1,
           :velocity => "2.0",
           :coordinate => [3, 3, 3],
           :time => (2, 3),
           :frequency => 5.0
       )

julia> A([d[name] for name in fieldnames(A)]...)
A(1, "2.0", [3, 3, 3], (2, 3), 5.0)

```

---

<div class="post-metadata">

**Author:** ![singularitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/singularitti/32/17678_2.png) [@singularitti](https://discourse.julialang.org/u/singularitti)\
**Post date:** [July 25, 2019, 6:56pm UTC](https://discourse.julialang.org/t/construct-an-immutable-type-from-a-dict/26709/9 "2019-07-25T18:56:40Z")

</div>

Yes, thank you. This was also pointed out in @yuyichao’s answer.

---

<div class="post-metadata">

**Author:** ![singularitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/singularitti/32/17678_2.png) [@singularitti](https://discourse.julialang.org/u/singularitti)\
**Post date:** [June 20, 2020, 9:55am UTC](https://discourse.julialang.org/t/construct-an-immutable-type-from-a-dict/26709/10 "2020-06-20T09:55:16Z")

</div>

> [@mauro3](#):
>
> `A(;Dict(:a=>1, :b=>3)...)`

It could be simplified to

```julia
A(; (:a=>1, :b=>3)...)

```

i.e., an iterator yielding pairs.  
A `Dict` is not necessary. Ref: [Essentials · The Julia Language](http://docs.julialang.org/en/v1/base/base/#Core.NamedTuple)
