# Initialization of container of constants? NamedTuple, etc

**URL:** <https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221>\
**Category:** General Usage\
**Created:** [July 19, 2024, 8:28am UTC](https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221 "2024-07-19T08:28:22Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)\
**Post date:** [July 19, 2024, 8:28am UTC](https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221/1 "2024-07-19T08:28:22Z")

</div>

Would there be some disadvantage in using a module as a container of constants?

I sometimes have 5–10 related global constants, which I sometimes want to treat as a whole. I thought that the simplest solution was

```julia
params = (a = 3.14, b = "hello", c = 6.28)
# . . . use params.a, etc. . . .

```

So far so good, but in my actual program, I need some of the parameters to depend on some others:

```julia
params = (
  a = 3.14
 ,b = "hello"
 ,c = func(a) 
)

```

which the compiler complains with “`a` not defined”.

You can fix this situation by

```julia
params = let
  a = 3.14
  (a = a, b = "hello", c = func(a))
end

```

This isn’t too bad, but if you have more parameters and more dependent ones, redundancy increases.

The good thing about the named tuple is that it’s simple and reads as a table of definitions with little redundancy. But, if you use the above `let` construct, that virtue is diminished.

Is there an elegant solution?

* * *

So, currently I’ve started to _abuse_ a nested module as a container:

```julia
module params
  a = 3.14
  b = "hello"
  c = Main.func(a)
end
# . . . use params.a, etc. . . .

```

Would there be disadvantages in this solution?

I’ve used modules to share constants between different programs or different modules of a single program, but I’ve never thought of using it as if it were a NamedTuple.

---

<div class="post-metadata">

**Author:** ![Sevi](https://avatars.discourse-cdn.com/v4/letter/s/c67d28/32.png) [@Sevi](https://discourse.julialang.org/u/Sevi)\
**Post date:** [July 19, 2024, 8:59am UTC](https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221/2 "2024-07-19T08:59:13Z")

</div>

> [@ryofurue](#):
>
> Would there be disadvantages in this solution?

I cannot really answer that, but I have an alternative suggestion that feels less like _abuse_ 😅

```julia
make_params(;
    a = 1,
    b = "hello",
    c = collect(a)
) = (; a, b, c)

```

Granted, it’s slightly more verbose than the module version, but I think it’s less confusing (at least for me). And if re-generating the parameters every time would be expensive, it’s straightforward to define a constant holding the results

```julia
const params = make_params()

```

Yet another way would be to make a struct, which is probably the most idiomatic for a “container of some values” (but I also like `NamedTuple` for its simplicity):

```julia
Base.@kwdef struct Params
    a::Float64 = 3.14
    b::String = "hello"
    c::Float64 = -a
end

```

Again, slightly more verbose due to type annotations (which you could also omit), but the intent is most clear here I think. The usage would be essentially the same as with the function, but with `@kwdef` you also have a nice syntax that already defines the constructor for you.

---

<div class="post-metadata">

**Author:** ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)\
**Post date:** [July 22, 2024, 7:11am UTC](https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221/3 "2024-07-22T07:11:59Z")

</div>

> [@Sevi](#):
>
> I cannot really answer that, but I have an alternative suggestion that feels less like _abuse_

Thanks for your interesting ideas! But, to me, your first solution feels _more_, rather than _less_, like _abuse_ 😉 because _you are using the keyword arguments of a function as a list of constants we want to encapsulate!_

Yes, I agree that your `struct` solution is more _proper_ than my _abuse_ of `module`.

---

<div class="post-metadata">

**Author:** ![DanielVandH](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielvandh/32/31134_2.png) [@DanielVandH](https://discourse.julialang.org/u/DanielVandH)\
**Post date:** [July 22, 2024, 7:22am UTC](https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221/4 "2024-07-22T07:22:37Z")

</div>

One issue with your approach as written is that your variables are all globals

```julia
julia> module params
       a = 3.14
       b = "hello"
       c = Main.func(a)
       end
Main.params

julia> @code_typed params.a
CodeInfo(
1 ─ %1 = Base.getglobal(x, f)::Any
└── return %1
) => Any

julia> @code_typed params.b
CodeInfo(
1 ─ %1 = Base.getglobal(x, f)::Any
└── return %1
) => Any

julia> @code_typed params.c
CodeInfo(
1 ─ %1 = Base.getglobal(x, f)::Any
└── return %1
) => Any

```

@Sevi’s method is probably the best to use. The keyword arguments wouldn’t cause any problem. If you know the constants won’t change and so don’t need the ability to specify them, then you can do

```julia
struct Params
a::Float64 
b::String 
c::Float64 
end
function Params()
a = 3.14 
b = "hello"
c = func(a)
return Params(a, b, c)
end

```

---

<div class="post-metadata">

**Author:** ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)\
**Post date:** [July 22, 2024, 7:50am UTC](https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221/5 "2024-07-22T07:50:44Z")

</div>

> [@DanielVandH](#):
>
> One issue with your approach as written is that your variables are all globals

That’s interesting. Thanks. I didn’t know that the compiler cannot get the type of the variables in the module:

```julia
julia> module params2
       const a = 3.14
       const b = "hello"
       const c = cos(a)
       end
Main.params2

julia> @code_typed params2.a
CodeInfo(
1 ─ %1 = Base.getglobal(x, f)::Any
└── return %1
) => Any

```

What about a NamedTuple?

```julia
julia> params3 = (a = 3.14, b = "hello")
(a = 3.14, b = "hello")

julia> @code_typed params3.a
CodeInfo(
1 ─ %1 = Base.getfield(x, f)::Union{Float64, String}
└── return %1
) => Union{Float64, String}

```

So, this one also potentially harms performance?

* * *

This makes me wonder: Does this mean that constants in other modules shouldn’t be used if you care about performance?

I’ve been long using modules to share read-only values between modules and programs.

* * *

You seem to say “global” as if it implies that its type cannot be determined at compile time. Is that always the case for globals?

---

<div class="post-metadata">

**Author:** ![DanielVandH](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielvandh/32/31134_2.png) [@DanielVandH](https://discourse.julialang.org/u/DanielVandH)\
**Post date:** [July 22, 2024, 7:57am UTC](https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221/6 "2024-07-22T07:57:41Z")

</div>

For your `params2`, if your code is in a function it works fine:

```julia
julia> module params2
       const a = 3.14
       const b = "hello"
       const c = cos(a)
       end
WARNING: replacing module params2.
Main.params2

julia> @code_typed params2.a # >:(
CodeInfo(
1 ─ %1 = Base.getglobal(x, f)::Any
└── return %1
) => Any

julia> function testf()
       return params2.a
       end
testf (generic function with 1 method)

julia> @code_typed testf() # :)
CodeInfo(
1 ─ return Main.params2.a
) => Float64

```

Not sure about the performance with named tuples, I never use them. If it’s `const` it figures it out though

```julia
julia> const p3 = (a = 3.14, b = "hello")
(a = 3.14, b = "hello")

julia> function g()
       return p3.a
       end
g (generic function with 1 method)

julia> @code_typed g()
CodeInfo(
1 ─ return 3.14
) => Float64

```

> Does this mean that constants in other modules shouldn’t be used if you care about performance?

Just make sure you’re using them in a function. If they’re correctly given a `const` tag its fine.

> You seem to say “global” as if it implies that its type cannot be determined at compile time. Is that always the case for globals?

Yes because the compiler doesn’t know if the global will change type. You can use typed globals if you do need to also change the variable, and the performance will improve a bit since it can infer the type.

```julia
julia> global x::Float64 = 3.14
3.14

julia> function h()
       return x
       end
h (generic function with 1 method)

julia> @code_typed h()
CodeInfo(
1 ─ %1 = Main.x::Float64
└── return %1
) => Float64

julia> badx = 3.14
3.14

julia> function hh()
       return badx
       end
hh (generic function with 1 method)

julia> @code_typed hh()
CodeInfo(
1 ─ %1 = Main.badx::Any
└── return %1
) => Any

```

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [July 22, 2024, 8:25am UTC](https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221/7 "2024-07-22T08:25:27Z")

</div>

> [@ryofurue](#):
>
> This makes me wonder: Does this mean that constants in other modules shouldn’t be used if you care about performance?

No you can’t really infer this from your tests. I think `@code_typed` applied to expressions in global scope is just not a good indicator for type stability.  
Consider:

```julia-repl
julia> module params2
       const a = 3.14
       const b = "hello"
       const c = cos(a)
       end

julia> @code_typed params2.a
CodeInfo(
1 ─ %1 = Base.getglobal(x, f)::Any
└── return %1
) => Any

julia> @code_typed (()->params2.a)() # same as above just wrapped in a function
CodeInfo(
1 ─ return Main.params2.a
) => Float64

```

This has nothing do with globals:

```julia
julia> let a = (5,"a")
       @code_typed a[1]
       end
CodeInfo(
1 ─ %1 = Base.getfield(t, i, $(Expr(:boundscheck)))::Union{Int64, String}
└── return %1
) => Union{Int64, String}

julia> let a = (5,"a",1.0,2im,π)
       @code_typed a[1]
       end
CodeInfo(
1 ─ %1 = Base.getfield(t, i, $(Expr(:boundscheck)))::Any
└── return %1
) => Any

julia> let a = (5,"a",1.0,2im,π)
       @code_typed (()->a[1])()
       end
CodeInfo(
1 ─ %1 = Core.getfield(#self#, :a)::Tuple{Int64, String, Float64, Complex{Int64}, Irrational{:π}}
│ %2 = Base.getfield(%1, 1, true)::Int64
└── return %2
) => Int64

```

I think, the thing here is that the type domain just does not carry the necessary information, i.e. indexing a `Tuple{Int,String}` with some `Int` could yield any of the contained types. However when you actually execute some piece of code then Julia has a lot more information: I this case the index `Int` is actually a constant and thus can be evaluated statically and that’s how Julia figures out that the return type actually will always be `Int`.  
In summary, I think `@code_typed` is just to primitive on its own. Wrap things in a function to get more accurate results!

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [July 22, 2024, 4:44pm UTC](https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221/8 "2024-07-22T16:44:08Z")

</div>

> [@ryofurue](#):
>
> ```julia
> (a = a, b = "hello", c = func(a))
> 
> ```
> 
> This isn’t too bad, but if you have more parameters and more dependent ones, redundancy increases.

You can somewhat reduce the redundancy, especially with longer names, by writing `a` only once: `(; a, b = "hello", c = func(a))`.

But generally, if `c` is some simple and cheap function of `a`, do you really need to store `c` at all?

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [July 22, 2024, 5:02pm UTC](https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221/9 "2024-07-22T17:02:57Z")

</div>

> [@ryofurue](#):
>
> ```julia
> params = let
> a = 3.14
> (a = a, b = "hello", c = func(a))
> end
> 
> ```

```julia
params = let
  a = 3.14
  (; a, b = "hello", c = func(a))
end

```

Add a `const` if this is at module/top-level scope.

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [July 22, 2024, 6:49pm UTC](https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221/10 "2024-07-22T18:49:31Z")

</div>

The package [AddToField.jl](https://github.com/pdeffebach/AddToField.jl), which I maintain, makes this pretty easy

```julia
julia> using AddToField

julia> @addnt begin
           @add a = 1
           @add b = a + 2
       end
(a = 1, b = 3)

```

---

<div class="post-metadata">

**Author:** ![Sevi](https://avatars.discourse-cdn.com/v4/letter/s/c67d28/32.png) [@Sevi](https://discourse.julialang.org/u/Sevi)\
**Post date:** [July 25, 2024, 8:14am UTC](https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221/11 "2024-07-25T08:14:21Z")

</div>

> [@ryofurue](#):
>
> But, to me, your first solution feels _more_, rather than _less_, like _abuse_ 😉 because _you are using the keyword arguments of a function as a list of constants we want to encapsulate!_

Fair point 🙂 As others pointed out already, the `let` block can also be made a bit less redundant and turned into something that visually looks a lot like the “function with keyword arguments” approach (the result would be the same).

```julia
params = let # or `const params` as discussed above
    a = 1
    b = "hello"
    c = collect(a)
    (; a, b, c)
end

```

---

<div class="post-metadata">

**Author:** ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)\
**Post date:** [August 15, 2024, 10:55am UTC](https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221/12 "2024-08-15T10:55:41Z")

</div>

Thank you all for your ideas.

I’ve learned (if I’m not mistaken) that a `module` is fine as long as the variables are declared `const` and these constants are used in functions.

Also, I like the “magic” `(; a, b, c)`:

> [@Sevi](#):
>
> ```julia
> params = let # or `const params` as discussed above
> a = 1
> b = "hello"
> c = collect(a)
> (; a, b, c)
> end
> 
> ```

---

<div class="post-metadata">

**Author:** ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)\
**Post date:** [August 15, 2024, 1:01pm UTC](https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221/13 "2024-08-15T13:01:36Z")

</div>

So, I guess my final question is, what’s so special about functions? It seems to me that you always want to put all your code in functions.

```julia
# (1) Potentially slow?
using MyModule
for i in 1:N
   # do some calculation using MyModule.x
end

```

may be slow because the type of `MyModule.x` may not be known.

```julia
# (2) Potentially faster?
using MyModule
function func()
  for i in 1:N
     # do some calculation using MyModule.x
  end
end
func()

```

Is that correct? If so, can’t the compiler mechanically translate code (1) into code (2) as an optimization?

I feel I must be missing something.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [August 15, 2024, 2:46pm UTC](https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221/14 "2024-08-15T14:46:42Z")

</div>

> [@ryofurue](#):
>
> may be slow because

It may be slower of faster compared to code in a function because code in a function is compiled before being executed.

> [@ryofurue](#):
>
> If so, can’t the compiler mechanically translate

Perhaps. But that wouldn’t really be desirable, I think. There needs to be a simple way to run Julia code without compiling it.

---

<div class="post-metadata">

**Author:** ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)\
**Post date:** [August 16, 2024, 4:52am UTC](https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221/15 "2024-08-16T04:52:17Z")

</div>

> [@nsajko](#):
>
> It may be slower of faster compared to code in a function because code in a function is compiled before being executed.

So, if I understand you correctly, the time it takes to compile the code is the only potential disadvantage.

If compilation is fast enough, we can always put everything in a function without any negative impacts. . . .

(Or do you mean that compilation _sometimes_ makes your code slower without taking the compilation time into account?)

But this is probably academic. When your code grows, you almost always split it into function calls, and your non-function (global) statements are always little.

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [August 16, 2024, 5:50am UTC](https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221/16 "2024-08-16T05:50:46Z")

</div>

> [@ryofurue](#):
>
> So, if I understand you correctly, the time it takes to compile the code is the only potential disadvantage.
> 
> If compilation is fast enough, we can always put everything in a function without any negative impacts. . . .

I think the more severe issue is that global scope has different (more dynamic) semantics. E.g. when it comes to the definition of new methods:

- The `for` loop in global scope redefines the function globally:

```julia-repl
julia> foo(x) = println("Foo: ",x)
foo (generic function with 1 method)

julia> for i in 1:5
       foo(x) = println("Foo: ",i," - ", x)
       foo(i)
       end
Foo: 1 - 1
Foo: 2 - 2
Foo: 3 - 3
Foo: 4 - 4
Foo: 5 - 5

julia> foo(6)
Foo: 5 - 6

```

- The `for` loop in a function does not:

```julia-repl
julia> foo(x) = println("Foo: ",x)
foo (generic function with 1 method)

julia> function bar() 
       for i in 1:5 
           foo(x) = println("Foo: ",i," - ", x)
           foo(i)
       end
       end
bar (generic function with 1 method)

julia> bar()
Foo: 1 - 1
Foo: 2 - 2
Foo: 3 - 3
Foo: 4 - 4
Foo: 5 - 5

julia> foo(6)
Foo: 6

```

- using `@eval` to redefine the function globally from inside the function, does mean that function body itself does not use the updated function:

```julia-repl
julia> foo(x) = println("Foo: ",x)
foo (generic function with 1 method)

julia> function bar() 
       for i in 1:5 
           @eval foo(x) = println("Foo: ", $i," - ", x)
           foo(i)
       end
       end
bar (generic function with 1 method)

julia> bar()
Foo: 1
Foo: 2
Foo: 3
Foo: 4
Foo: 5

julia> foo(6)
Foo: 5 - 6

```

- So you’d need to use `Base.invokelatest` in the function to restore the previous behavior faithfully. But performing the transformation from the top-level code to a function and littering every call with `Base.invokelatest` does not allow for any compiler optimization and is essentially equivalent to how top-level code is run anyways.

> [@ryofurue](#):
>
> If so, can’t the compiler mechanically translate code (1) into code (2) as an optimization?

So I conclude, that this transformation is not mechanical for it to be actually useful.

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [August 16, 2024, 6:12am UTC](https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221/17 "2024-08-16T06:12:51Z")

</div>

Parameters.jl

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [August 16, 2024, 8:23am UTC](https://discourse.julialang.org/t/initialization-of-container-of-constants-namedtuple-etc/117221/18 "2024-08-16T08:23:05Z")

</div>

> [@ryofurue](#):
>
> So, if I understand you correctly, the time it takes to compile the code is the only potential disadvantage.

That’s what I meant, yeah. But, as @abraemer shows, the different semantics might be of significance, too.
