# Defining const inside struct

**URL:** <https://discourse.julialang.org/t/defining-const-inside-struct/49866>\
**Category:** General Usage\
**Created:** [November 9, 2020, 7:53pm UTC](https://discourse.julialang.org/t/defining-const-inside-struct/49866 "2020-11-09T19:53:53Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [November 9, 2020, 7:53pm UTC](https://discourse.julialang.org/t/defining-const-inside-struct/49866/1 "2020-11-09T19:53:53Z")

</div>

This is a follow-up of this thread, which ended with this new issue I am not sure how to solve:

[https://discourse.julialang.org/t/nightly-build-ci-failing-because-rand-unitrange-changed-when-to-care/49857/10](https://discourse.julialang.org/t/nightly-build-ci-failing-because-rand-unitrange-changed-when-to-care/49857/10)

The issue is the following: The usage of my package starts with the user defining a series of options which are organized in a struct. Now I want to add to that `struct` the possibility of the user defining which is the random number generator to be used. I am using `Parameters`, so I have default options:

```julia
using Parameters
@with_kw struct Options
   # ... other fields
   seed :: Int64 = 321
   rng = Random.MersenneTwister(seed)
end

```

The problem with this is that, the user will initialize these options with, in the simplest case:

```julia
opt = Options()

```

which leads to the situation that using `rand(rng)` allocates memory:

```julia
julia> @allocated rand(opt.rng)
31353

julia> @allocated rand(opt.rng)
48

```

If the `opt` instance was constant, the allocations go away:

```julia
julia> const opt2 = Options()
Options
  seed: Int64 321
  rng: Random.MersenneTwister

julia> @allocated(opt2.rng)
0

```

I do not want to impose to the user the use `const opt = ....`, this would be quite cumbersome, because then he/she would have to change the variable name every time in a script to run the package with different options.\*

I am unsure how to proceed here. I need `rng` to be a constant, but which can be optionally defined and yet having a default value if nothing is defined by the user. It does not need to be a part of the `Options` structure, it can be a global variable (changing its value will be a very rare situation, actually only during package testing).

I ended up with the idea that I could pass a parameter for the module during loading, but that feature was not implemented because it seems that better solutions were found every time.

\*Telling the user to wrap everything inside a `let` block, or a function, is also not an option here. Everything computationally demanding in this package is done by other function which receives those options as a parameter, and that is perfectly fine, fast, with no allocations, except now for the necessity of giving the user the option to change the random number generator.

---

<div class="post-metadata">

**Author:** ![Skoffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skoffer/32/378_2.png) [@Skoffer](https://discourse.julialang.org/u/Skoffer)\
**Post date:** [November 9, 2020, 8:10pm UTC](https://discourse.julialang.org/t/defining-const-inside-struct/49866/2 "2020-11-09T20:10:51Z")

</div>

Parameters output is deceiving, this is actuall abstract type putfall: [Performance Tips · The Julia Language](https://docs.julialang.org/en/v1/manual/performance-tips/#Avoid-fields-with-abstract-type)

You can avoid it by using parametrized struct

```julia
@with_kw struct Options2{T}
   # ... other fields
   seed :: Int64 = 321
   rng :: T = Random.MersenneTwister(seed)
end

```

and it’s better to test it somewhere where you can see that allocations do not multiply

```julia
function f(opts)
    res = 0.
    for i in 1:100
        res += rand(opts.rng)
    end
    return res
end

```

```julia
opt = Options()
opt2 = Options2()

julia> @allocated f(opt)
3200

julia> @allocated f(opt2)
16

```

Or you can verify that your code is type stable with `@code_warntype`

```julia
julia> @code_warntype f(opt)
Variables
  #self#::Core.Compiler.Const(f, false)
  opts::Options
  res::Any
  @_4::Union{Nothing, Tuple{Int64,Int64}}
  i::Int64

Body::Any
....

julia> @code_warntype f(opt2)
Variables
  #self#::Core.Compiler.Const(f, false)
  opts::Options2{MersenneTwister}
  res::Float64
  @_4::Union{Nothing, Tuple{Int64,Int64}}
  i::Int64

Body::Float64

```

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [November 9, 2020, 8:14pm UTC](https://discourse.julialang.org/t/defining-const-inside-struct/49866/3 "2020-11-09T20:14:50Z")

</div>

Thank you. I tested that, but as your example shows, it still allocates (less, but still).

---

<div class="post-metadata">

**Author:** ![Skoffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skoffer/32/378_2.png) [@Skoffer](https://discourse.julialang.org/u/Skoffer)\
**Post date:** [November 9, 2020, 8:17pm UTC](https://discourse.julialang.org/t/defining-const-inside-struct/49866/4 "2020-11-09T20:17:31Z")

</div>

This is unavoidable and not related to rng or anything else. This is just REPL working with global variables.

```julia
function f(x)
    res = 0.
    for i in 1:100
        res += x
    end
    res
end

x = 10.

julia> @allocated f(x)
16

julia> function g()
           x = 10.0

           f(x)
       end
g (generic function with 1 method)

julia> @allocated g()
0

```

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [November 9, 2020, 8:19pm UTC](https://discourse.julialang.org/t/defining-const-inside-struct/49866/5 "2020-11-09T20:19:57Z")

</div>

Uhm… I will check that out in the actual code. Of course there the calls to `rand` are inside functions, such that those allocations should not appear. I have the impression of having tested that, but maybe I didn’t after parameterizing the struct type. I hope that is the problem. Thanks again.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [November 10, 2020, 1:04am UTC](https://discourse.julialang.org/t/defining-const-inside-struct/49866/6 "2020-11-10T01:04:45Z")

</div>

Just for completeness. The problem I was having was that one, but with a small complicator. The `Options` structure above was being inherited (very likely this is not the correct word in computer science for this) by other structure, which I had to parameterize as well to get rid of all allocations. Something like this:

```julia
using Parameters
import Random

@with_kw struct Options{T}
  seed :: Int64 = 321
  rng :: T = Random.MersenneTwister(seed)
end

struct ComputeData
  opt :: Options
end

```

Changing `ComputeData` to this solved the problem completely:

```julia
struct ComputeData{T}
  opt :: Options{T}
end

```

Otherwise I still got some allocations in the use of rand inside the main function, although I could not track that with `@code_warntype` really.

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [November 10, 2020, 2:47am UTC](https://discourse.julialang.org/t/defining-const-inside-struct/49866/7 "2020-11-10T02:47:10Z")

</div>

The field of `ComputeData` had an abstract type, instead of the concrete type, you changed to the concrete type and solved the problem.

The word is _composed_ (as a struct is _composed_ of its fields, and putting a field `T` inside a struct instead inheriting the type `T` is often referred as _using composition instead of inheritance_).
