# 'Reducing' scope of global variables in functions

**URL:** <https://discourse.julialang.org/t/reducing-scope-of-global-variables-in-functions/43256>\
**Category:** General Usage\
**Tags:** question\
**Created:** [July 17, 2020, 7:30pm UTC](https://discourse.julialang.org/t/reducing-scope-of-global-variables-in-functions/43256 "2020-07-17T19:30:44Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![1ozturkbe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/1ozturkbe/32/16461_2.png) [@1ozturkbe](https://discourse.julialang.org/u/1ozturkbe)\
**Post date:** [July 17, 2020, 7:30pm UTC](https://discourse.julialang.org/t/reducing-scope-of-global-variables-in-functions/43256/1 "2020-07-17T19:30:44Z")

</div>

I have a question with respect to globals in functions. I rely a lot on generating functions inside functions that take in data arguments. However, I am finding that changing the data (eg. a and idxs in the global scope below) are changing my functions. I haven’t been able to figure out how to fix a and idxs when I generate the functions so the output does not change, eg. would always return 74 below.

```julia
a = [1,2,3,4,5];
idxs = [2,3,4];
x = [6,7,8,9,10];
fn = x -> sum(a[idxs].*x[idxs]);
fn(x) # 74, initially.
idxs = [1,2]; # Changing indices...
fn(x) # 20, changes value of function.
# Changes in 'a' have a similar effect;
a = [0,2,3,4,5];
fn(x) # 14

```

I have tried some global/local hackery and copying of a and idxs but that doesn’t help. Let me know how to get around this issue. Sorry in advance if this is really elementary, Julia is not my strong suit.

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [July 17, 2020, 7:36pm UTC](https://discourse.julialang.org/t/reducing-scope-of-global-variables-in-functions/43256/2 "2020-07-17T19:36:29Z")

</div>

You can use a `let` block to ensure that the `a` and `idxs` inside `fn` refer to a captured _copy_ of the external variables:

```julia
julia> a = [1,2,3,4,5];

julia> idxs = [2,3,4];

julia> x = [6,7,8,9,10];

julia> fn = let a = copy(a), idxs = copy(idxs)
         # inside this `let` block, `a` and `idxs` refer to the local *copies*
         x -> sum(a[idxs] .* x[idxs])
       end
#13 (generic function with 1 method)

julia> fn(x)
74

julia> idxs .= [1, 2]
2-element Array{Int64,1}:
 1
 2

julia> fn(x)
74

```

---

<div class="post-metadata">

**Author:** ![1ozturkbe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/1ozturkbe/32/16461_2.png) [@1ozturkbe](https://discourse.julialang.org/u/1ozturkbe)\
**Post date:** [July 18, 2020, 8:16pm UTC](https://discourse.julialang.org/t/reducing-scope-of-global-variables-in-functions/43256/3 "2020-07-18T20:16:18Z")

</div>

Thanks for the prompt reply. That was really helpful, but also really frustrating. Because yes, the above works in the ‘map’ method of writing functions, but if I try with a traditional function declaration, it fails!

```julia
a_mat = [[1,2,3,4,5],
         [2,3,4,5,6],
         [3,4,5,6,7]];
x = [6,7,8,9,10];
fns = [];
for i=1:3
    function fn(x)
        let a = copy(a_mat[i])
        return sum(a.*x);
        end
    end
    push!(fns, fn);
end
println([i(x) for i in fns]) # [130, 170,210]
a_mat[2][2] = 10;
println([i(x) for i in fns]) # [130, 219, 210]

```

What is the difference between what we were doing above and here? Thanks again.

---

<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:** [July 18, 2020, 8:17pm UTC](https://discourse.julialang.org/t/reducing-scope-of-global-variables-in-functions/43256/4 "2020-07-18T20:17:38Z")

</div>

Pass the global variables as arguments to the functions and you will avoid all such issues.

---

<div class="post-metadata">

**Author:** ![1ozturkbe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/1ozturkbe/32/16461_2.png) [@1ozturkbe](https://discourse.julialang.org/u/1ozturkbe)\
**Post date:** [July 18, 2020, 8:22pm UTC](https://discourse.julialang.org/t/reducing-scope-of-global-variables-in-functions/43256/5 "2020-07-18T20:22:31Z")

</div>

I would prefer to not have to pass optional arguments to each function, but I guess that would be a way to get around this issue. I just figured that there must be a less painful method. Also, frankly I don’t understand the difference between the two examples I provided.

---

<div class="post-metadata">

**Author:** ![1ozturkbe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/1ozturkbe/32/16461_2.png) [@1ozturkbe](https://discourse.julialang.org/u/1ozturkbe)\
**Post date:** [July 18, 2020, 8:29pm UTC](https://discourse.julialang.org/t/reducing-scope-of-global-variables-in-functions/43256/6 "2020-07-18T20:29:31Z")

</div>

Actually, rather hilariously, passing globals as optional arguments doesn’t work either, a la:

```julia
    function fn(x, a = copy(a_mat[i]))
        return sum(a.*x);
    end

```

When a is modified, the output is still changed. I guess I will keep searching for a solution.

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [July 18, 2020, 8:59pm UTC](https://discourse.julialang.org/t/reducing-scope-of-global-variables-in-functions/43256/7 "2020-07-18T20:59:23Z")

</div>

> [@1ozturkbe](#):
>
> What is the difference between what we were doing above and here?

You’ve put your `let` block _inside_ the function body, while I put mine _outside_ the function body. In your example, the global `a_mat` is copied every time you call `fn`, and then work is done with that fresh copy. That doesn’t accomplish your goal of isolating the behavior of the function from external changes to `a_mat` because every call to `fn` just copies whatever `a_mat[i]` happens to be right now. You need to do the copy exactly once, when the function is defined, and putting the function definition inside the `let` block is a nice trick for accomplishing that.

You can achieve the behavior you want by doing:

```julia
fn = let a = copy(a_mat[i])
  function (x)
    return sum(a .* x)
  end
end

```

or

```julia
let a = copy(a_mat[i])
  global fn # we need this otherwise the `fn` will only
             # be a local variable in the `let` block
  function fn(x)
    return sum(a .* x)
  end
end

```

---

<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:** [July 18, 2020, 9:14pm UTC](https://discourse.julialang.org/t/reducing-scope-of-global-variables-in-functions/43256/8 "2020-07-18T21:14:44Z")

</div>

I misunderstood the question.  
But it sounds like doing this and later modifying the global arrays will lead to confusing code, where the reader will exactly be wondering which version of what is being used where.

You can just copy the initial values into new arrays which are never modified and use those inside the functions.

---

<div class="post-metadata">

**Author:** ![1ozturkbe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/1ozturkbe/32/16461_2.png) [@1ozturkbe](https://discourse.julialang.org/u/1ozturkbe)\
**Post date:** [July 19, 2020, 2:28am UTC](https://discourse.julialang.org/t/reducing-scope-of-global-variables-in-functions/43256/9 "2020-07-19T02:28:45Z")

</div>

> [@rdeits](#):
>
> ```julia
> fn = let a = copy(a_mat[i])
> function (x)
> return sum(a .* x)
> end
> end
> 
> ```

Alright, now I am getting my head around it. I used the first for clarify and worked perfectly. Thanks!

---

<div class="post-metadata">

**Author:** ![1ozturkbe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/1ozturkbe/32/16461_2.png) [@1ozturkbe](https://discourse.julialang.org/u/1ozturkbe)\
**Post date:** [July 19, 2020, 2:34am UTC](https://discourse.julialang.org/t/reducing-scope-of-global-variables-in-functions/43256/10 "2020-07-19T02:34:04Z")

</div>

Thanks for the feedback and the help @dpsanders! Part of the issue is that the supposed ‘globals’ are products of functions called inside functions in a loop. It has been a serious challenge making code that is robust to potential scope issues.
