# How to make a vector of parametric composite types?

**URL:** <https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439>\
**Category:** New to Julia\
**Created:** [March 4, 2017, 1:35pm UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439 "2017-03-04T13:35:11Z")\
**Posts on this page:** 20\
**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 4, 2017, 1:35pm UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/1 "2017-03-04T13:35:11Z")

</div>

Hello everyone,  
I 've been using Julia for a few months now, and I really love it, especially the type system.

I’m working on a code to compute the optical reflectivity of a multilayer. The multilayer is a stack of homogeneous plane parallel media (layers). Each layer has a thickness and optical properties.

For now I’m using singleton types for the optical properties, but it seems this is not recommended and I would like to use value types instead. But I don’t manage to implement this.  
I’m using Julia 0.5.0.

This is how I’m handling the simulations now.  
I first define an abstract type OptProp

```julia
abstract OptProp

```

I then define singleton types for different materials

```julia
immutable Sic <: OptProp end
immutable Al <: OptProp end
immutable Vac <: OptProp end

```

This allows me to dispatch on the permittivity function to obtain the optical properties for each of those materials.  
For instance for the optical properties of Aluminium I use:

```julia
function permittivity(material :: Al(), frequency)
     some code
end

```

and similarly for other materials.

I then define the layer type

```julia
immutable Layer
    material :: OptProp
    thickness :: Float64
end

```

A multilayer is then a vector of the Layer type. As an example, an interface between vacuum and alumium would be defined as

```julia
interface = [Layer(Vac(),0.0); Layer(Al(),0.0)]

```

More complex multilayers can be constructed adding layers with other materials and thickness.  
This works fine, but I’m not sure this is the recommended way.

I tried to implement the “value type” -approach, but I didn’t succeed.  
Here is what I tried:

```julia
immutable Mater{T}<: OptProp
end

immutable Layer{T}
    material :: Mater{T}
    thickness :: Float64
end

```

This new version of the Layer type does not work.  
If I do for a semi-infinite medium of aluminium:

```julia
Layer(Mater{:al},0.0)

```

I get a MethodError : no method matching Layer{T}(::Type{Mater{:al}},:: Float64)

I have three questions:

1. Is there an overhead defining vectors of composite types containing singleton types (first approach)?
2. Is it recommended/more efficient to use value types for the material properties, instead of the singleton types?
3. If the answer to question 2 is yes, how would you actually implement it?

Many thanks in advance.  
Olivier

---

<div class="post-metadata">

**Author:** ![braydenware](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/braydenware/32/2612_2.png) [@braydenware](https://discourse.julialang.org/u/braydenware)\
**Post date:** [March 5, 2017, 2:26am UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/2 "2017-03-05T02:26:42Z")

</div>

The error arises from a mismatch between the singleton type and the instance of the singleton type. You can avoid it by either modifying the constructor call Layer(Mater{:al}, 0.0) to look like “Layer(Mater{:al}(),0.0)” (i.e. creating an instance of the Mater{:al}) OR by changing the field in the type definition of Layer to “material :: Type{Mater{T}}”.

---

<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 5, 2017, 10:03pm UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/3 "2017-03-05T22:03:37Z")

</div>

Thank you very much for your answer.  
That works.

It seems, however, that the value type approach generates much more allocation than the singleton type one.

Value type :

```julia
@time ml = [Layer(Mater{:vac},0.0) ; Layer(Mater{:al},0.0)]
0.000294 seconds (52 allocations: 2.125 KB)

```

Where the layer type was defined as

```julia
immutable Layer{T}
    material :: Type{Mater{T}}
    thickness :: Float64
end

```

with

```julia
immutable Mater{T} <: OptProp end

```

For the singleton type approach I get:

```julia
@time ml = [Layer(Vac(),0.0) ; Layer(Al(),0.0)]
0.000012 seconds (7 allocations: 320 bytes)

```

I used @code\_warntype on both approaches and it seems the ‘value type’ method is type unstable while the singleton one is not.

Is this expected behaviour?  
Thanks again

---

<div class="post-metadata">

**Author:** ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)\
**Post date:** [March 6, 2017, 7:47am UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/4 "2017-03-06T07:47:06Z")

</div>

That is interesting, I get the same. I wonder why this is.  
BTW is there a reason for not using the slightly (imho) simpler syntax

```julia
abstract OptProp

immutable Al <: OptProp end
immutable Vac <: OptProp end

immutable Layer{T <: OptProp}
    material::Type{T}
    thickness::Float64
end

 @time ml = [Layer(Al,0.0) ; Layer(Vac,0.0)]

```

---

<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 6, 2017, 1:05pm UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/5 "2017-03-06T13:05:41Z")

</div>

@mkborregaard Thanks a lot for pointing out the simpler syntax.

With this third approach I get the same timing and allocations as for the ‘value type’ approach

```julia
@time ml = [Layer(Al,0.0) ; Layer(Vac,0.0)]
 0.000267 seconds (52 allocations: 2.125 KB)

```

Doing `@code_warntype`, indicates a type instability on `Type{T}`

For completeness I have to add that the results in my answer to @braydenware were obtained on a windows machine.  
The results in this post were obtained on a different machine with UBUNTU 14.04.  
But apparently the results are the same in both cases.

From this, it seems I should stick with the singleton type approach with the syntax

```julia
abstract OptProp

immutable Sic <: OptProp end
immutable Al <: OptProp end
immutable Vac <: OptProp end

 immutable Layer
    material :: OptProp
    thickness :: Float64
end

```

Which I don’t find very satisfying since for every new material, I have to introduce a new immutable type.

Furthermore, if I understand the documentation correctly, for better performance, fields of composite types should be concrete types or parametric which is in contradiction with the above example.  
Am I missing some crucial point here?

---

<div class="post-metadata">

**Author:** ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)\
**Post date:** [March 6, 2017, 1:28pm UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/6 "2017-03-06T13:28:20Z")

</div>

So I am not sure exactly what you want. Maybe instead you are looking for something like this?

```julia
@enum Material Sic Al Vac

immutable Layer
   material::Material
   thickness::Float64
end

permittivity(l::Layer) = permittivity(Val{l.material})

function permittivity(::Type{Val{Al}})
   println("The permittivity of Aluminum is grand indeed")
end

function permittivity(::Type{Val{Sic}})
   println("But even grander is Silicium")
end

#Then
l = Layer(Al, 4)
permittivity(l)
l2 = Layer(Sic, 4)
permittivity(l2)

```

```julia
@time ml = [Layer(Al,0.0) ; Layer(Vac,0.0)]
  0.000008 seconds (7 allocations: 336 bytes)

```

---

<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 6, 2017, 2:24pm UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/7 "2017-03-06T14:24:52Z")

</div>

Woow, thanks a lot!  
This is really nice.  
It will make the code much more user friendly.

Thanks again  
Olivier

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [March 6, 2017, 2:47pm UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/8 "2017-03-06T14:47:44Z")

</div>

I think this will cause calculating the `permitivity` to be slow, since it will be doing dynamic (runtime) dispatch.

Would it be possible to use a dictionary for the permitivities instead?

---

<div class="post-metadata">

**Author:** ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)\
**Post date:** [March 6, 2017, 3:03pm UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/9 "2017-03-06T15:03:46Z")

</div>

> [@dpsanders](#):
>
> I think this will cause calculating the permitivity to be slow, since it will be doing dynamic (runtime) dispatch.

You’re right.

```julia
@enum Material Sic Al Vac

immutable Layer
          material::Material
          thickness::Float64
       end

permittivity(l::Layer) = permittivity(Val{l.material})
permittivity (generic function with 1 method)

function permittivity(::Type{Val{Sic}})
          2
       end

using BenchmarkTools

@benchmark permittivity(l2)
BenchmarkTools.Trial: 
  memory estimate: 16 bytes
  allocs estimate: 1
  --------------
  minimum time: 331.807 ns (0.00% GC)
  median time: 335.516 ns (0.00% GC)
  mean time: 346.447 ns (0.45% GC)
  maximum time: 8.241 μs (93.95% GC)
  --------------
  samples: 10000
  evals/sample: 223
  time tolerance: 5.00%
  memory tolerance: 1.00%

```

vs

```julia
abstract OptProp

immutable Al <: OptProp end

immutable Layer{T <: OptProp}
           material::Type{T}
           thickness::Float64
       end

function permittivity{T<:Al}(x::Layer{T})
       2
end
l1 = Layer(Al, 0.)

using BenchmarkTools
@benchmark permittivity(l1)
BenchmarkTools.Trial: 
  memory estimate: 0 bytes
  allocs estimate: 0
  --------------
  minimum time: 12.587 ns (0.00% GC)
  median time: 12.725 ns (0.00% GC)
  mean time: 12.890 ns (0.00% GC)
  maximum time: 46.025 ns (0.00% GC)
  --------------
  samples: 10000
  evals/sample: 999
  time tolerance: 5.00%
  memory tolerance: 1.00%

```

Thanks! (and sorry @Olivier_Merchiers)

---

<div class="post-metadata">

**Author:** ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)\
**Post date:** [March 6, 2017, 4:35pm UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/10 "2017-03-06T16:35:32Z")

</div>

@Olivier_Merchiers can you give a little more info - e.g. why do you use dispatch on the permittivity function?

---

<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 6, 2017, 4:57pm UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/11 "2017-03-06T16:57:14Z")

</div>

Thanks for this correction.

But there remains the issue with allocation and time for the vector of layers with this implementation:

```julia
abstract OptProp

immutable Al <: OptProp end
immutable Vac <: OptProp end

immutable Layer{T <: OptProp}
          material::Type{T}
          thickness::Float64
 end

@benchmark ml = [Layer(Al,0.0); Layer(Vac,0.0)]
BenchmarkTools.Trial: 
  memory estimate: 1.97 kb
  allocs estimate: 48
  --------------
  minimum time: 10.937 μs (0.00% GC)
  median time: 11.656 μs (0.00% GC)
  mean time: 11.802 μs (0.00% GC)
  maximum time: 72.133 μs (0.00% GC)
  --------------
  samples: 10000
  evals/sample: 1
  time tolerance: 5.00%
  memory tolerance: 1.00%

```

While with

```julia
abstract OptProp

immutable Al <: OptProp end
immutable Vac <: OptProp end

immutable Layer
          material::OptProp
          thickness::Float64
 end

@benchmark ml = [Layer(Al(),0.0); Layer(Vac(),0.0)]
BenchmarkTools.Trial: 
  memory estimate: 160.00 bytes
  allocs estimate: 3
  --------------
  minimum time: 43.866 ns (0.00% GC)
  median time: 47.852 ns (0.00% GC)
  mean time: 61.659 ns (21.21% GC)
  maximum time: 2.199 μs (96.82% GC)
  --------------
  samples: 10000
  evals/sample: 990
  time tolerance: 5.00%
  memory tolerance: 1.00%

```

This is quite important for me, since I need to pass such multilayer structures to other functions that will compute reflectivity and other physical quantities.

Finally, doing the test with the permittivity function

```julia
function permittivity(x::Al)
              2
       end

```

I get

```julia
@benchmark permittivity(Al())
BenchmarkTools.Trial: 
  memory estimate: 0.00 bytes
  allocs estimate: 0
  --------------
  minimum time: 1.409 ns (0.00% GC)
  median time: 1.680 ns (0.00% GC)
  mean time: 1.711 ns (0.00% GC)
  maximum time: 90.449 ns (0.00% GC)
  --------------
  samples: 10000
  evals/sample: 1000
  time tolerance: 5.00%
  memory tolerance: 1.00%

```

Which is almost 10 times faster.

---

<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 6, 2017, 5:15pm UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/12 "2017-03-06T17:15:51Z")

</div>

@mkborregaard Sorry, I missed this last question before submitting the other reply.

> [@mkborregaard](#):
>
> @Olivier_Merchiers can you give a little more info - e.g. why do you use dispatch on the permittivity function?

Yes of course.  
I need to make reflectivity calculations for many different materials. These materials have optical properties that are defined by their permittivity function.  
With every material corresponds a unique permittivity function which returns a complex number.  
This number is used to compute the reflectivity.

To keep my code generic, and not using if-then-else in a big permittivity function containing all possible definitions for each material, I wanted to use multiple dispatch to get the right permittivity method corresponding with each material.

To give some examples:  
For vacuum this would be

```julia
permittivity(material::Vacuum) = 1.0 +im*0.0

```

For frequency dependent (hence w in the parameter list) optical properties you would have something like

```julia
function permittivity(material::Cbn,w) 
    eps_fin = 4.46 + 0.0*im 
    w_lo = 2.451e14 # rad/s 
    w_to = 1.985e14 # rad/s 
    gamma = 9.934e11 # rad/s 
    return eps_fin*(w^2-w_lo^2 + im*gamma*w)/(w^2-w_to^2 + im*gamma*w) 
end

```

Let me know if this explanation is not clear

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [March 6, 2017, 6:06pm UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/13 "2017-03-06T18:06:26Z")

</div>

That’s why I suggested to use a dictionary instead of the big `if-else`.

---

<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 6, 2017, 6:32pm UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/14 "2017-03-06T18:32:14Z")

</div>

How would you implement such a Dict?

If the permittivity for each material was a constant value, I think I could build such a dict.  
But this is not the case here, since the permittivity for each material is a function of the frequency as shown in this example:

```julia
function permittivity(material::Cbn,w) 
    eps_fin = 4.46 + 0.0*im 
    w_lo = 2.451e14 # rad/s 
    w_to = 1.985e14 # rad/s 
    gamma = 9.934e11 # rad/s 
    return eps_fin*(w^2-w_lo^2 + im*gamma*w)/(w^2-w_to^2 + im*gamma*w) 
end

```

where w is the frequency in rad/s and can take any real value between 0 and infinity.

That would imply a dict of functions?  
Did I misunderstand your suggestion?

---

<div class="post-metadata">

**Author:** ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)\
**Post date:** [March 6, 2017, 7:46pm UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/15 "2017-03-06T19:46:53Z")

</div>

Well maybe your original model is best, I really don’t see what is wrong with it 🙂 But the reason your last permittivity function is fast is because there is no dispatch at all.  
You could have concrete parametric functions in your first example like

```julia
    abstract OptProp

    immutable Al <: OptProp end
    immutable Vac <: OptProp end

    immutable Layer{T <: OptProp}
              material::T
              thickness::Float64
    end

# and then
    permittivity{T <: Al}(l::Layer{T}) = 2

# or the clearer
   permittivity(l::Layer) = permittivity(l.material)
   permittivity(x::Al) = 2

```

Note that in benchmark it is important how to set it up for comparison

```julia
l = Layer(Al(), 0.)
@benchmark permittivity(l)
BenchmarkTools.Trial: 
  memory estimate: 0 bytes
  allocs estimate: 0
  --------------
  minimum time: 15.057 ns (0.00% GC)
  median time: 15.652 ns (0.00% GC)
  mean time: 15.877 ns (0.00% GC)
  maximum time: 46.872 ns (0.00% GC)
  --------------
  samples: 10000
  evals/sample: 998
  time tolerance: 5.00%
  memory tolerance: 1.00%

@benchmark permittivity(Layer(Al(), 0.))
BenchmarkTools.Trial: 
  memory estimate: 0 bytes
  allocs estimate: 0
  --------------
  minimum time: 1.500 ns (0.00% GC)
  median time: 1.502 ns (0.00% GC)
  mean time: 1.506 ns (0.00% GC)
  maximum time: 3.348 ns (0.00% GC)
  --------------
  samples: 10000
  evals/sample: 1000
  time tolerance: 5.00%
  memory tolerance: 1.00%

```

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [March 6, 2017, 11:49pm UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/16 "2017-03-06T23:49:24Z")

</div>

> [@mkborregaard](#):
>
> permittivity(Layer(Al(), 0.))

You need to interpolate:

```julia
@benchmark permittivity($l)

```

This then gives the same time.

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [March 6, 2017, 11:50pm UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/17 "2017-03-06T23:50:39Z")

</div>

See [here](https://github.com/JuliaCI/BenchmarkTools.jl/blob/master/doc/manual.md#interpolating-values-into-benchmark-expressions) for details about interpolation.

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [March 6, 2017, 11:55pm UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/18 "2017-03-06T23:55:10Z")

</div>

This seems to be the best solution.

---

<div class="post-metadata">

**Author:** ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)\
**Post date:** [March 7, 2017, 6:02am UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/19 "2017-03-07T06:02:09Z")

</div>

Thanks, this is great - in trying to help I also (re-)learn some useful things myself. I only hope this hasn’t created too much noise for anyone reading this thread 🙂

---

<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, 2017, 9:02am UTC](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439/20 "2017-03-07T09:02:01Z")

</div>

Thanks a lot for your help @mkborregaard, @dpsanders.

This was really instructive. Things are much clearer now to me.

With the interpolation, the benchmark results for the vector of Layers become also identical for the different approaches even with the enum type approach. Too bad the enum types are slow for the permittivity calculation. I really liked them 🙂

[Next page](https://discourse.julialang.org/t/how-to-make-a-vector-of-parametric-composite-types/2439.md?page=2)
