# Local scope rules are confusing in inner scopes (Julia 1.6)

**URL:** https://discourse.julialang.org/t/local-scope-rules-are-confusing-in-inner-scopes-julia-1-6/64936
**Category:** General Usage
**Created:** [July 19, 2021, 5:08pm UTC](https://discourse.julialang.org/t/local-scope-rules-are-confusing-in-inner-scopes-julia-1-6/64936 "2021-07-19T17:08:06Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![wsshin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsshin/32/360_2.png) [@wsshin](https://discourse.julialang.org/u/wsshin)
#### Post date: [July 19, 2021, 5:08pm UTC](https://discourse.julialang.org/t/local-scope-rules-are-confusing-in-inner-scopes-julia-1-6/64936/1 "2021-07-19T17:08:06Z")

</div>

I am using Julia 1.6.1:

```julia
julia> VERSION
v"1.6.1-pre.1"

```

I find the local scope rules are confusing to apply to inner scopes (such as inner functions). The rules are described at described at [Scope of Variables · The Julia Language](https://docs.julialang.org/en/v1/manual/variables-and-scoping/#Local-Scope) and copied below:

1. **Existing local:** If `x` is _already a local variable_ , then the existing local `x` is assigned;
2. **Hard scope:** If `x` is _not already a local variable_ and assignment occurs inside of any hard scope construct (i.e. within a let block, function or macro body, comprehension, or generator), a new local named `x` is created in the scope of the assignment;
3. **Soft scope:** If `x` is _not already a local variable_ and all of the scope constructs containing the assignment are soft scopes (loops, `try` / `catch` blocks, or `struct` blocks), the behavior depends on whether the global variable `x` is defined:

- **a**. if global `x` is _undefined_ , a new local named `x` is created in the scope of the assignment;
- **b**. if global `x` is _defined_ , the assignment is considered ambiguous:
  - **i**. in _non-interactive_ contexts (files, eval), an ambiguity warning is printed and a new local is created;
  - **ii**. in _interactive_ contexts (REPL, notebooks), the global variable `x` is assigned.

Now, consider this example:

```julia
function funout()
    global x = 1

    function funin()
        x = 2
    end

    funin()

    return x # x is global variable
end

```

Here, the inner function `funin()` creates a hard scope. The assignment `x = 1` before the definition of `funin()` is global (not local), so I thought the assignment `x = 2` inside `funin()` would create a new local variable according to Rule 2 above. However, executing `funout()` actually updates the global variable:

```julia
julia> funout()
2

julia> x # global variable
2

```

Consider another example:

```julia
function myfun()
    global x = 1

    for i = 1:3
        x = i
    end

    return x
end

```

Here, the `for` loop inside the function `myfun()` creates a soft scope. Again, the assignment `x = 1` before the `for` loop is global (not local). Therefore, the above definition of `myfun()` is put in a file and and executed, I thought Rule 3.b.i would apply. However, neither an ambiguity warning is generated, nor the assignment `x = i` in the `for` loop creates a new local variable:

```julia
julia> code = """function myfun()
           global x = 1

           for i = 1:3
               x = i
           end

           return x
       end

       myfun()
       """;

julia> include_string(Main, code)
3

julia> x # global variable
3

```

Based on these examples, I feel that something is missing from the description of the local scope rules in the documentation. Are there any exceptions to the rules related to the inner scopes or the usage of the `global` keyword?

**UPDATE.** I realized that Rule 3 applies when all the scopes enclosing the assignment are soft scopes. So Rule 3.b.i does not apply to the second example because `myfun()` is a hard scope. But then, the local scope rules don’t seem to specify what happens to the assignment inside a soft scope enclosed by a hard scope.

---

<div class="post-metadata">

### Author: ![jeff.bezanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff.bezanson/32/48_2.png) [@jeff.bezanson](https://discourse.julialang.org/u/jeff.bezanson)
#### Post date: [July 20, 2021, 2:03am UTC](https://discourse.julialang.org/t/local-scope-rules-are-confusing-in-inner-scopes-julia-1-6/64936/2 "2021-07-20T02:03:52Z")

</div>

Yes, I think the explanation in the manual — despite quite a bit of revising over the years — is still not ideal. Overall, I think too much has been made of the hard- vs. soft-scope distinction. The way I think about it is that once you are inside a scope that can have local variables (e.g. `let`, `for`, or a function), everything follows very simple lexical scope rules: all variables and declarations are inherited by inner scopes. Things are only weird in the very first transition from global to local scope. That’s the only place “hardness” matters: for some forms (e.g. functions), we’ll always introduce new locals by default, and for others “it depends”. But once inside the comfort of a local scope, you don’t need to know which scopes are “hard”; they all behave the same — or at least they should!! Any exceptions will be entertained as bug reports.
