# Confused about scope

**URL:** <https://discourse.julialang.org/t/confused-about-scope/3405>\
**Category:** New to Julia\
**Created:** [April 27, 2017, 4:00pm UTC](https://discourse.julialang.org/t/confused-about-scope/3405 "2017-04-27T16:00:02Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![antoine-levitt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/antoine-levitt/32/4008_2.png) [@antoine-levitt](https://discourse.julialang.org/u/antoine-levitt)\
**Post date:** [April 27, 2017, 4:00pm UTC](https://discourse.julialang.org/t/confused-about-scope/3405/1 "2017-04-27T16:00:02Z")

</div>

Hi,

```julia
module test
a = 1
function f()
    println(a)
end
end

```

module.f() prints 1, as expected.

```julia
module test
a = 1
function f()
    a = 2
    println(a)
end
end

```

This prints 2, but afterwards test.a is 1. I was expecting that a is a global variable seen from f() (consistent with the previous example), and therefore I can modify it. What am I understanding wrong here?

```julia
module test
a = 1
function f()
    println(a)
    a = 2
end
end

```

Errors because a is not defined! I guess this is because the compiler sees the “a = 2” after and therefore declares a as a local variable, but this is very surprising.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [April 27, 2017, 4:01pm UTC](https://discourse.julialang.org/t/confused-about-scope/3405/2 "2017-04-27T16:01:07Z")

</div>

> [@antoine-levitt](#):
>
> Errors because a is not defined! I guess this is because the compiler sees the “a = 2” after and therefore declares a as a local variable, but this is very surprising.

It is surprising but that is the case.

---

<div class="post-metadata">

**Author:** ![malmaud](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/malmaud/32/29_2.png) [@malmaud](https://discourse.julialang.org/u/malmaud)\
**Post date:** [April 27, 2017, 4:40pm UTC](https://discourse.julialang.org/t/confused-about-scope/3405/3 "2017-04-27T16:40:03Z")

</div>

How else could it work, though? The scope of `a` can’t change within a block, so it can’t matter where `a=2` happens within the block.

---

<div class="post-metadata">

**Author:** ![dfdx](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dfdx/32/120_2.png) [@dfdx](https://discourse.julialang.org/u/dfdx)\
**Post date:** [April 27, 2017, 5:01pm UTC](https://discourse.julialang.org/t/confused-about-scope/3405/4 "2017-04-27T17:01:39Z")

</div>

> [@antoine-levitt](#):
>
> This prints 2, but afterwards test.a is 1. I was expecting that a is a global variable seen from f() (consistent with the previous example), and therefore I can modify it. What am I understanding wrong here?

Assignment inside a block\* introduces a new variable, regardless of what variables are available outside. It’s very sensible if you think about it. Imagine, for example, that you write a function `f()` that uses a local variable `a` and _later_ refactor your module to also have a global variable `a`. Should `f()` now work differently? I guess you would like `f()` to keep the same behavior because it’s totally unrelated to the global variable `a`.

I know very few cases for global variables, but if you really need them, try adding a `global` modifier to them in local scope. E.g. in:

```julia
module test
a = 1
function f()
    global a = 2
    println(a)
end
end

```

`a` will refer to the global variable instead of introducing a new local one.

_\*_ - there are several types of blocks in Julia, see [docs](https://docs.julialang.org/en/stable/manual/variables-and-scoping/) for more information.

---

<div class="post-metadata">

**Author:** ![antoine-levitt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/antoine-levitt/32/4008_2.png) [@antoine-levitt](https://discourse.julialang.org/u/antoine-levitt)\
**Post date:** [April 27, 2017, 5:05pm UTC](https://discourse.julialang.org/t/confused-about-scope/3405/5 "2017-04-27T17:05:01Z")

</div>

What I’m confused about is the status of variables in modules, as seen inside functions. The first example seems to suggest they are global, but then why can’t I modify them in the second example? The third example is surprising (adding a definition of a later in the function makes it undefined!) but makes sense, I agree.

---

<div class="post-metadata">

**Author:** ![dfdx](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dfdx/32/120_2.png) [@dfdx](https://discourse.julialang.org/u/dfdx)\
**Post date:** [April 27, 2017, 5:11pm UTC](https://discourse.julialang.org/t/confused-about-scope/3405/6 "2017-04-27T17:11:46Z")

</div>

> [@antoine-levitt](#):
>
> The first example seems to suggest they are global, but then why can’t I modify them in the second example?

In your second example, there are 2 different variables with the same name, one global and one local.

---

<div class="post-metadata">

**Author:** ![antoine-levitt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/antoine-levitt/32/4008_2.png) [@antoine-levitt](https://discourse.julialang.org/u/antoine-levitt)\
**Post date:** [April 27, 2017, 6:45pm UTC](https://discourse.julialang.org/t/confused-about-scope/3405/7 "2017-04-27T18:45:44Z")

</div>

dfdx: sorry, I was writing my message at the same time as you.

OK, the “an assignment introduces a local variable” semantics seems clear. Could a warning maybe be printed in such cases, though? It seems very error-prone.

Adding to my confusion was the fact that [https://groups.google.com/d/msg/julia-users/FBTEhEJKOCo/VBDHYKKfdWkJ](https://groups.google.com/d/msg/julia-users/FBTEhEJKOCo/VBDHYKKfdWkJ) suggests that variables in an outer scope can be accessed and modified, but that the snipped shown there does not work (maybe it was for a previous version of julia?)

My use case is a simple package with numerical parameters being used in many functions. Instead of passing them around all the time, I figured it would be simpler to use them as globals. I could have a global “parameters” structure, but then I’d have to either refer to the parameters as eg params.N or unpack them at the beginning of the functions (I saw there’s a package for that). If there’s anything simpler I’m all ears.

---

<div class="post-metadata">

**Author:** ![shorty66](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/shorty66/32/3254_2.png) [@shorty66](https://discourse.julialang.org/u/shorty66)\
**Post date:** [April 27, 2017, 6:52pm UTC](https://discourse.julialang.org/t/confused-about-scope/3405/8 "2017-04-27T18:52:46Z")

</div>

Variables are first searched in function bodys. If they are not defined in the function, only a global variable can be meant.  
Whenever a function defines a local version of a, a only ever refers to that local variable.

Your first case falls back to global search and is indeed the exception.

Perhaps we could need something like [Pythons LEGB rule](http://stackoverflow.com/questions/291978/short-description-of-the-scoping-rules)…

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [April 27, 2017, 7:50pm UTC](https://discourse.julialang.org/t/confused-about-scope/3405/9 "2017-04-27T19:50:57Z")

</div>

> [@antoine-levitt](#):
>
> My use case is a simple package with numerical parameters being used in many functions. Instead of passing them around all the time, I figured it would be simpler to use them as globals. I could have a global “parameters” structure, but then I’d have to either refer to the parameters as eg params.N or unpack them at the beginning of the functions (I saw there’s a package for that). If there’s anything simpler I’m all ears.

Give Parameters.jl a try. You’ll notice it really isn’t much more code, and now all of your parameters are local variables.

---

<div class="post-metadata">

**Author:** ![dfdx](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dfdx/32/120_2.png) [@dfdx](https://discourse.julialang.org/u/dfdx)\
**Post date:** [April 27, 2017, 9:05pm UTC](https://discourse.julialang.org/t/confused-about-scope/3405/10 "2017-04-27T21:05:34Z")

</div>

> [@antoine-levitt](#):
>
> OK, the “an assignment introduces a local variable” semantics seems clear. Could a warning maybe be printed in such cases, though? It seems very error-prone.

Again, this would change the behavior of the function without actually touching its code. The general approach in literally every (non-esoteric) programming language I know is to minimize the perception border of the code you read or write. One way to do it is to keep control flow local, i.e. write code in small independent chunks that you can reason about without looking at any other place. Imagine, that you read somebody’s large module and see a function:

```julia
function f()
    a = 2
    println(a)
end

```

What can you tell about `a`? With Julia’s scoping rules you definitely know that `a` is local, it doesn’t affect any global variables and this code doesn’t cause any warnings. From only 4 lines of code, you _know exactly_ what will happen when you call this function. In addition, you can now introduce a global variable `a` somewhere in the module without worrying to affect any of local variables.

With global variables, it becomes much harder to reason about the code because in this case you have to keep in mind all the code, not just a little piece.

In your case I’d create a struct to keep all parameters together and pass it to all functions. Something like:

```julia
mutable struct Params 
    a::Int
    b::Float64
    c::String
end

function foo(p::Params, ...)
    ...
    p.a = 2
    println(p.a)
    ...
end

```

(use `type` instead of `mutable struct` if you are on Julia 0.5)

This way you need just a bit more keystrokes, but code maintainability increases drastically.

---

<div class="post-metadata">

**Author:** ![antoine-levitt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/antoine-levitt/32/4008_2.png) [@antoine-levitt](https://discourse.julialang.org/u/antoine-levitt)\
**Post date:** [April 28, 2017, 7:53pm UTC](https://discourse.julialang.org/t/confused-about-scope/3405/11 "2017-04-28T19:53:39Z")

</div>

I still like the simplicity of globals, but point taken. Thanks for the clarification!

Shouldn’t the following raise a warning at parse time, though? I suppose the user could mean a local variable but it seems more likely than not that it’s a bug.

` module A a = 1 function f() a = 2 end end`

---

<div class="post-metadata">

**Author:** ![ohsonice](https://avatars.discourse-cdn.com/v4/letter/o/d6d6ee/32.png) [@ohsonice](https://discourse.julialang.org/u/ohsonice)\
**Post date:** [April 28, 2017, 9:49pm UTC](https://discourse.julialang.org/t/confused-about-scope/3405/12 "2017-04-28T21:49:13Z")

</div>

I’m partial to Golang’s subtle assignment vs declaration syntax.

`:=` declaration  
`=` assignment

---

<div class="post-metadata">

**Author:** ![fengyang.wang](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fengyang.wang/32/104_2.png) [@fengyang.wang](https://discourse.julialang.org/u/fengyang.wang)\
**Post date:** [April 29, 2017, 12:20am UTC](https://discourse.julialang.org/t/confused-about-scope/3405/13 "2017-04-29T00:20:30Z")

</div>

My experience with Lint.jl suggests that the vast majority of the time this happens, it’s not a bug. Lint has a I341 message for this case (local variable shadowing global); it’s ignored by default because of how noisy it gets.

In practice, most modules do not often contain functions that modify global variables. There are a variety of reasons for this, not least being that non-const global variables are bad for performance. However, it is very common to use a local variable name identical to that of a global variable.
