# How can I avoid using global variables that will vary their values?

**URL:** <https://discourse.julialang.org/t/how-can-i-avoid-using-global-variables-that-will-vary-their-values/99085>\
**Category:** Performance\
**Created:** [May 18, 2023, 9:47pm UTC](https://discourse.julialang.org/t/how-can-i-avoid-using-global-variables-that-will-vary-their-values/99085 "2023-05-18T21:47:37Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![AliceandBob](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aliceandbob/32/50045_2.png) [@AliceandBob](https://discourse.julialang.org/u/AliceandBob)\
**Post date:** [May 18, 2023, 9:47pm UTC](https://discourse.julialang.org/t/how-can-i-avoid-using-global-variables-that-will-vary-their-values/99085/1 "2023-05-18T21:47:37Z")

</div>

I am using Julia to solve a quantum system with a self-consistence iteration algorithm. In my current code, many global variables and arrays are used which, from many documents, are harmful to the performance. However, I don’t know how to avoid this. I post the structure of my code here and wonder how to improve it.

Part 1:  
I will define some parameters that describe the system and calculate something from them. These things are global. They will be useful and stay unchanged in Part 2 but will be changed in Part 3.

```julia
# define some parameters that will be constant
const m = 1.1 # electron mass
const ManyOtherParameters = ...

# define some parameters that will be changed
B = 2.2 # magnetic field
d = 3.3 # some meaningful distance
ManyOtherThings = ...

# calculate some useful things from magnetic field and other things
# This step consumes a lot of time
function CalculateArray(Mag = B, Dis = d)
    ...
    # calculation
    ...

    return Array
end
A = CalculateArray(B, d)

# an interface to change magnetic field and other parameters that will be useful in Part 3
function ChangeParameters(; Mag = B, Dis = d, OtherThings...)
    global B = Mag
    global d = Dis
    ...
    global A = CalculateArray(B, d)
end

```

Part 2:  
I will solve the system using the global variables in Part 1.

```julia
# one step of iteration
function Solve_OneStep(initialSolution = 0.0)
    ...
    # use B, d, A and initialSolution to find out renewedSolution
    ...
    return renewedSolution
end

# Solve the system
function Solve(initialSolution = 0.0; ControlParameters...)
    solution = initialSolution 
    for i in 1:IterationTimes # for example, 1000
        ...
        # iteration
        ...
    end
    return solution
end

```

Part 3:  
I will vary the system parameters and see how the result changes. For example, I will change the value of these global variables, solve it, and record the solution.

```julia
using CairoMakie

# set the parameters first
ChangeParameters(Mag = 0.5, Dis = 2.0, OtherThings...)

# the varying range for magnetic field
B_range = 0. : 0.1 : 20.
results = similar(B_range, Float64)

# solve the system for each magnetic fields
for i in eachindex(B_range)
    ChangeParameters(Mag = B_range[i])
    results[i] = Solve()
end

# plot the results
lines(B_range, results)

```

---

<div class="post-metadata">

**Author:** ![greatpet](https://avatars.discourse-cdn.com/v4/letter/g/e495f1/32.png) [@greatpet](https://discourse.julialang.org/u/greatpet)\
**Post date:** [May 18, 2023, 10:04pm UTC](https://discourse.julialang.org/t/how-can-i-avoid-using-global-variables-that-will-vary-their-values/99085/2 "2023-05-18T22:04:28Z")

</div>

Try this. Pack all your global variables into an instance `parameters` of a mutable struct `MyParameters`.

```julia
mutable struct MyParameters
    b::Float64
    d::Float64
end

const parameters = MyParameters(2.2, 3.3) # the memory address is constant but the values of `b` and `d` can be changed.

```

Any function that uses these parameters needs to take the above struct as an additional argument. For example, instead of  
`function solve_one_step(initial_solution = 0.0)`  
define it as  
`function solve_one_step(parameters::MyParameters, initial_solution = 0.0)`  
so that the function can access, for example, `parameters.b`.

Then you can change parameters by mutating the struct,

```julia
function change_parameters!(parameters::MyParameters, mag, dis) # mutating functions end with `!` by convention
    parameters.b = mag
    parameters.d = dis
end

```

Now always pass `parameters` as an argument when you call these functions.

P.S. Alternatively, pack your parameters into a normal (non-mutable) struct `MyParameters`. First compute with `parameters1::MyParameters`, and when you need to compute with a different set of parameters, compute again with `parameters2::MyParameters`, i.e. instead of changing the values in `parameters1`.

---

<div class="post-metadata">

**Author:** ![AliceandBob](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aliceandbob/32/50045_2.png) [@AliceandBob](https://discourse.julialang.org/u/AliceandBob)\
**Post date:** [May 18, 2023, 11:06pm UTC](https://discourse.julialang.org/t/how-can-i-avoid-using-global-variables-that-will-vary-their-values/99085/3 "2023-05-18T23:06:07Z")

</div>

Thanks for your suggestion. But should I also include my global array A in this struct?

---

<div class="post-metadata">

**Author:** ![Jeff\_Emanuel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff_emanuel/32/15440_2.png) [@Jeff\_Emanuel](https://discourse.julialang.org/u/Jeff_Emanuel)\
**Post date:** [May 18, 2023, 11:13pm UTC](https://discourse.julialang.org/t/how-can-i-avoid-using-global-variables-that-will-vary-their-values/99085/4 "2023-05-18T23:13:44Z")

</div>

Don’t modify A in your function. Change it in the calling code.

> [@AliceandBob](#):
>
> ```julia
> function ChangeParameters(; Mag = B, Dis = d, OtherThings...)
> global B = Mag
> global d = Dis
> ...
> return CalculateArray(B, d) # return keyword is unnecessary here, BTW.  
> end
> 
> A = ChangeParameters(....)
> 
> ```

And functions that read A should accept it in the function parameters.

---

<div class="post-metadata">

**Author:** ![j-fu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/j-fu/32/11373_2.png) [@j-fu](https://discourse.julialang.org/u/j-fu)\
**Post date:** [May 19, 2023, 12:28am UTC](https://discourse.julialang.org/t/how-can-i-avoid-using-global-variables-that-will-vary-their-values/99085/5 "2023-05-19T00:28:07Z")

</div>

Also consider using [`@kwdef`](https://docs.julialang.org/en/v1/base/base/#Base.@kwdef) - this significantly will ease default initialization.

---

<div class="post-metadata">

**Author:** ![LeePhillips](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/leephillips/32/205514_2.png) [@LeePhillips](https://discourse.julialang.org/u/LeePhillips)\
**Post date:** [May 19, 2023, 2:38am UTC](https://discourse.julialang.org/t/how-can-i-avoid-using-global-variables-that-will-vary-their-values/99085/6 "2023-05-19T02:38:41Z")

</div>

Julia v.1.8 introduced non-constant typed globals  
([Julia 1.8 Highlights](https://julialang.org/blog/2022/08/julia-1.8-highlights/)). If you declare the types of your non-constant globals there’s a good chance that they won’t give give you a performance hit.

---

<div class="post-metadata">

**Author:** ![AliceandBob](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aliceandbob/32/50045_2.png) [@AliceandBob](https://discourse.julialang.org/u/AliceandBob)\
**Post date:** [May 19, 2023, 5:58am UTC](https://discourse.julialang.org/t/how-can-i-avoid-using-global-variables-that-will-vary-their-values/99085/7 "2023-05-19T05:58:43Z")

</div>

That’s cool. Thanks.

---

<div class="post-metadata">

**Author:** ![AliceandBob](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aliceandbob/32/50045_2.png) [@AliceandBob](https://discourse.julialang.org/u/AliceandBob)\
**Post date:** [May 19, 2023, 5:59am UTC](https://discourse.julialang.org/t/how-can-i-avoid-using-global-variables-that-will-vary-their-values/99085/8 "2023-05-19T05:59:47Z")

</div>

That does help.

---

<div class="post-metadata">

**Author:** ![AliceandBob](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aliceandbob/32/50045_2.png) [@AliceandBob](https://discourse.julialang.org/u/AliceandBob)\
**Post date:** [May 19, 2023, 6:07am UTC](https://discourse.julialang.org/t/how-can-i-avoid-using-global-variables-that-will-vary-their-values/99085/9 "2023-05-19T06:07:15Z")

</div>

I do not really understand. The array is still global in your code. Do you mean changing a global array globally is better than changing it in a function? Also, I see other people saying that passing a global array to functions does not help much in performance because Julia passes arrays by referring. Is that true?

---

<div class="post-metadata">

**Author:** ![AliceandBob](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aliceandbob/32/50045_2.png) [@AliceandBob](https://discourse.julialang.org/u/AliceandBob)\
**Post date:** [May 19, 2023, 6:34am UTC](https://discourse.julialang.org/t/how-can-i-avoid-using-global-variables-that-will-vary-their-values/99085/10 "2023-05-19T06:34:36Z")

</div>

Thanks for all advice. But I am still confused about the global array A.

Actually, the value of elements of it is used more frequently in the following solving functions so it is more important. And because calculating it costs time, I choose to store it in a global array instead of calculating it in the functions that need it.

The element type and number of dimensions of A are fixed, but the sizes of each dimension may vary with different magnetic fields.

Can I put it in the struct that stores all the parameters? Can I simply claim it with the keyword const? Just leaving it global and passing it as an argument to the functions that use it?

---

<div class="post-metadata">

**Author:** ![greatpet](https://avatars.discourse-cdn.com/v4/letter/g/e495f1/32.png) [@greatpet](https://discourse.julialang.org/u/greatpet)\
**Post date:** [May 19, 2023, 7:00am UTC](https://discourse.julialang.org/t/how-can-i-avoid-using-global-variables-that-will-vary-their-values/99085/11 "2023-05-19T07:00:09Z")

</div>

> [@AliceandBob](#):
>
> Can I put it in the struct that stores all the parameters?

Yes, you can put the array in a struct. My suggestion was packing all global variables (arrays or not) into a struct.

---

<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:** [May 19, 2023, 11:29am UTC](https://discourse.julialang.org/t/how-can-i-avoid-using-global-variables-that-will-vary-their-values/99085/12 "2023-05-19T11:29:19Z")

</div>

Summarizing what people said: You can do something like this:

```julia
# system definition with default values
julia> @kwdef struct System{T}
           m::T = 1.1 # electron mass
           B::T = 2.2 # magnetic field
           d::T = 3.3 # some meaningful distance
           # ... other properties
       end

# Function that calculates something
julia> function calculate_something(system::System)
           # unpack (for convevienence, otherwise use system.m
           (; m, B, d) = system
           return m * B * d
       end
calculate_someting (generic function with 1 method)

# Initialize the system with the properties, potentially changing something
julia> system = System(d = 5.3)
System{Float64}(1.1, 2.2, 5.3)

julia> calculate_something(system)
12.826000000000002

```

Now for a different set of properties you initialize a new system. This is the most idiomatic way, probably. And you don’t use global variables at all inside your functions. Everything will easier to understand and debug.

Your `System` struct can contain output variables as well. If they are arrays you can just add them there, because arrays are mutable. But one generally separates the properties of the _input_ from the properties of the _output_. I would keep `System` as the _input_ of the calculation, and keep it immutable.

ps: If you really need your system to be _mutable_, that is, you want to be able to redefine one of a few variables from a system that is very different from the default, make it a `mutable struct`. Or, alternatively, you can use `Accessors` and create a new system by copying the `system` you have, changing something specific:

```julia
julia> using Accessors

julia> system2 = @set system.d = 1.0
System{Float64}(1.1, 2.2, 1.0)

```

---

<div class="post-metadata">

**Author:** ![Jeff\_Emanuel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff_emanuel/32/15440_2.png) [@Jeff\_Emanuel](https://discourse.julialang.org/u/Jeff_Emanuel)\
**Post date:** [May 19, 2023, 1:30pm UTC](https://discourse.julialang.org/t/how-can-i-avoid-using-global-variables-that-will-vary-their-values/99085/13 "2023-05-19T13:30:57Z")

</div>

The important part is whether the variable is global, not the value that the variable is bound to. The compiler can’t generate fast code for non-constant global _variables_. If code in a function operates on a global _variable_ then the function can’t be fast. When you pass the array to the function the array is bound to a local variable in the function and the compiler can usually generate fast code. (You still must avoid type instability in the function)

---

<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:** [May 19, 2023, 1:44pm UTC](https://discourse.julialang.org/t/how-can-i-avoid-using-global-variables-that-will-vary-their-values/99085/14 "2023-05-19T13:44:38Z")

</div>

A good advice (not only in Julia) is: try to avoid referencing global variables _always_. There are not many cases where you really need to use them (really). Make all function self-contained, meaning, variables inside that function are either received as parameters (packed into structs, tuples, or not), or defined inside the function.

That will avoid these performance traps and, importantly, make your code much easier to debug, optimize, etc, because you will be able to test and develop each function independently from the rest of the code, just providing a sensible input data to it.

---

<div class="post-metadata">

**Author:** ![Jeff\_Emanuel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff_emanuel/32/15440_2.png) [@Jeff\_Emanuel](https://discourse.julialang.org/u/Jeff_Emanuel)\
**Post date:** [May 19, 2023, 2:21pm UTC](https://discourse.julialang.org/t/how-can-i-avoid-using-global-variables-that-will-vary-their-values/99085/15 "2023-05-19T14:21:45Z")

</div>

Emphasizing @lmiq’s advice: [https://dl.acm.org/doi/10.1145/953353.953355](https://dl.acm.org/doi/10.1145/953353.953355) [https://www.baeldung.com/cs/global-variables](https://www.baeldung.com/cs/global-variables)
