# Best way to create a struct with a variable data contents

**URL:** https://discourse.julialang.org/t/best-way-to-create-a-struct-with-a-variable-data-contents/21580
**Category:** General Usage
**Created:** [March 7, 2019, 3:29pm UTC](https://discourse.julialang.org/t/best-way-to-create-a-struct-with-a-variable-data-contents/21580 "2019-03-07T15:29:58Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![Olivier\_Merchiers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/olivier_merchiers/32/4073_2.png) [@Olivier\_Merchiers](https://discourse.julialang.org/u/Olivier_Merchiers)
#### Post date: [March 7, 2019, 3:29pm UTC](https://discourse.julialang.org/t/best-way-to-create-a-struct-with-a-variable-data-contents/21580/1 "2019-03-07T15:29:58Z")

</div>

Hello everyone,

I’m trying to create a mini materials database. In this database, I would have materials which can have a varying number of properties: optical, electrical, thermal …  
Each material can have only one of those, some of those or all of those.

I thought to create a type Material in which the data is kept in a dict:

```julia
struct Material{K,V <: Description}
    data :: Dict{K,V}
end

```

where depending on the property I can have a description that can change (using a model or data)

```julia
abstract type Description end
struct Model <: Description end
struct SomeData <: Description end

```

I would then describe silicon in the following way

```julia
Si = Material( Dict(:optical => Model(), 
                     :electrical => SomeData()) )

```

Now I can compute some properties:

```julia
permitivitty(material :: Material{K,V}) where {K,V<:Description} = permitivitty(material.data[:optical])
permitivitty(::Model) = "model"
permitivitty(::SomeData) = "some data"

```

This works as expected

```julia
julia> permitivitty(Si)
"model"

```

This approach works, but I don’t like too much how to declare the materials.

I have three questions:

1. I’m wondering if there is a better way to describe the data in the Material struct.
2. Is there a less verbose way to declare the material (maybe linked to the first question)?
3. how can I produce a message “no optical properties defined” when I’m computing the permittivity of a material for which there is no :optical key?

Many thanks in advance,  
Olivier

---

<div class="post-metadata">

### Author: ![JonasIsensee](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jonasisensee/32/4704_2.png) [@JonasIsensee](https://discourse.julialang.org/u/JonasIsensee)
#### Post date: [March 7, 2019, 3:56pm UTC](https://discourse.julialang.org/t/best-way-to-create-a-struct-with-a-variable-data-contents/21580/2 "2019-03-07T15:56:54Z")

</div>

Concerning question three:  
There is a function `haskey(key)` which checks if a `Dict` contains a key-value pair with  
given key.

---

<div class="post-metadata">

### Author: ![jbrea](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jbrea/32/3879_2.png) [@jbrea](https://discourse.julialang.org/u/jbrea)
#### Post date: [March 7, 2019, 4:12pm UTC](https://discourse.julialang.org/t/best-way-to-create-a-struct-with-a-variable-data-contents/21580/3 "2019-03-07T16:12:11Z")

</div>

If you don’t need to add properties after instantiation, you could wrap a `NamedTuple` instead of a `Dict`, i.e.

```julia
struct Material{K,V}
       data::NamedTuple{K,V}
end
Material(; kwargs...) = Material(kwargs.data)
Si = Material(optical = Model(), electrical = SomeData())
function permitivitty(material :: Material{K,V}) where {K,V}
    if :optical in K
         permitivitty(material.data.optical)
    else
         @warn "$material has no propery optical"
    end
end

```

---

<div class="post-metadata">

### Author: ![Olivier\_Merchiers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/olivier_merchiers/32/4073_2.png) [@Olivier\_Merchiers](https://discourse.julialang.org/u/Olivier_Merchiers)
#### Post date: [March 7, 2019, 5:24pm UTC](https://discourse.julialang.org/t/best-way-to-create-a-struct-with-a-variable-data-contents/21580/4 "2019-03-07T17:24:47Z")

</div>

This is indeed much nicer.  
Thanks again

---

<div class="post-metadata">

### Author: ![asprionj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/asprionj/32/6856_2.png) [@asprionj](https://discourse.julialang.org/u/asprionj)
#### Post date: [March 7, 2019, 10:49pm UTC](https://discourse.julialang.org/t/best-way-to-create-a-struct-with-a-variable-data-contents/21580/5 "2019-03-07T22:49:20Z")

</div>

Hi, just thought about the following solution:

```julia
# Union for descriptions: either a description, or nothing
DescriptionUnion = Union{Description, Nothing}

struct Material
    optical::DescriptionUnion
    electrical::DescriptionUnion
end

# keyword-arguments constructor (could be generated by a macro for convenience...)
Material(;optical=nothing, electrical=nothing) = Material(optical, electrical)

# possible usage
Material(nothing, SomeData()) # default constructor
Material() # all fields are "nothing"
Material(optical=Model()) # set some of the data fields

```

Then you’d define functions on material properties as:

```julia
permitivitty(material :: Material) = permitivitty(material.optical)
permitivitty(::Model) = "model"
permitivitty(::SomeData) = "some data"
permitivitty(::Nothing) = @warn "optical properties undefined"

```

I’m also relatively new to Julia, so I’ve no idea whether this is a good solution or not…

---

<div class="post-metadata">

### Author: ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)
#### Post date: [March 8, 2019, 4:28am UTC](https://discourse.julialang.org/t/best-way-to-create-a-struct-with-a-variable-data-contents/21580/6 "2019-03-08T04:28:55Z")

</div>

IMO @asprionj’s solution is a lot better, since it comes with type safety… if you use a dictionary or named tuple, a typo in one of your properties will result in a bug (as if the material is missing that property), vs refusing to create the material in the first place. (Of course, you could detect that even with a dictionary by adding verification code in the constructor, but that seems a lot messier.)

If you think this won’t be an issue in practice, consider that you already have a typo in the word “permitivitty” in your code 🙂

---

<div class="post-metadata">

### Author: ![jbrea](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jbrea/32/3879_2.png) [@jbrea](https://discourse.julialang.org/u/jbrea)
#### Post date: [March 8, 2019, 7:36am UTC](https://discourse.julialang.org/t/best-way-to-create-a-struct-with-a-variable-data-contents/21580/7 "2019-03-08T07:36:52Z")

</div>

The compiler may prefer a parametric type

```julia
struct Material{To,Te}
    optical::To
    electrical::Te
end

```

Look e.g. at `m = Material(optical=Model()); @code_warntype permitivitty(m)`.  
If there are only two properties, I would also go with this approach. But I understood the OP that there can be many more properties, and then I see a trade-off between convenience (the `NamedTuple`-approach) and typo-safety (the explicit parametric struct approach). In terms of performance they should be equivalent.

---

<div class="post-metadata">

### Author: ![Olivier\_Merchiers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/olivier_merchiers/32/4073_2.png) [@Olivier\_Merchiers](https://discourse.julialang.org/u/Olivier_Merchiers)
#### Post date: [March 8, 2019, 8:53am UTC](https://discourse.julialang.org/t/best-way-to-create-a-struct-with-a-variable-data-contents/21580/8 "2019-03-08T08:53:36Z")

</div>

Indeed, after benchmarking I see that  
method 1 : @jbrea 's first solution gives

```julia
@btime permitivitty($Si)
  1.688 ns (0 allocations: 0 bytes)

```

method 2 : @asprionj 's solution gives

```julia
  @btime permitivitty($Si2)
  4.203 ns (0 allocations: 0 bytes)

```

method 3: parametric type instead of union gives again

```julia
@btime permitivitty($Si)
  1.688 ns (0 allocations: 0 bytes)

```

> But I understood the OP that there can be many more properties, and then I see a trade-off between convenience (the `NamedTuple` -approach) and typo-safety

I agree 200%  
In my case I don’t have too many properties, but if for some reason I have a material for which I want to add other properties, the NamedTuple allows me to keep the types as they are.

Thanks to all of you for looking into this.  
I learned a lot again.
