# I thought I understood "pass-by-sharing" in Julia until I found this

**URL:** https://discourse.julialang.org/t/i-thought-i-understood-pass-by-sharing-in-julia-until-i-found-this/46897
**Category:** General Usage
**Created:** [September 19, 2020, 5:59am UTC](https://discourse.julialang.org/t/i-thought-i-understood-pass-by-sharing-in-julia-until-i-found-this/46897 "2020-09-19T05:59:11Z")
**Posts on this page:** 2
**Page:** 2

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [September 21, 2020, 5:52am UTC](https://discourse.julialang.org/t/i-thought-i-understood-pass-by-sharing-in-julia-until-i-found-this/46897/23 "2020-09-21T05:52:32Z")

</div>

> [@pauljurczak](#):
>
> otherwise searching for keywords like `outer` is futile

The search facility is steadily getting better, I think in this particular case the problem is really the documentation for `outer`. See

> <https://github.com/JuliaLang/julia/issues/37492>
>
> As title says, should at least show up in:
> 1. https://docs.julialang.org/en/v1.…6-dev/manual/control-flow/#man-loops
> 2. \`?outer\`

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [September 21, 2020, 4:12pm UTC](https://discourse.julialang.org/t/i-thought-i-understood-pass-by-sharing-in-julia-until-i-found-this/46897/24 "2020-09-21T16:12:43Z")

</div>

Yes, both maybe would not match what OP expected, even elucidating this misconception. There are others things at play, but mostly, they are related to how closures work, and after understanding the scope problem, I think they become minor details.

> [@greg\_plowman](#):
>
> ```julia
> anon = Array{Any}(undef, 2)
> for i = 1:2
> anon[i] = ()-> println(i)
> i += 1
> end
> anon[1]()
> anon[2]()
> 
> ```

This gives

```julia
2
3

```

and I suppose you mean the expected would be

```julia
1
2

```

What happens here is that the first closure captures the binding `i` in the first scope, and the second closure captures the binding `i` in the second scope. Moreover, both closures are **callled after the loop has ended**. The `i` of the first scope, at the ends of its loop/scope, has value `2`, and the `i` of the second scope, at the ends of its loop/scope, has value `3`. These both distinct `i`s keep existing because they are referred by the closure, and they print the last value they had. If you did:

```julia
anon = Array{Any}(undef, 2)
for i = 1:2
    # the nothing below is just to avoid extra printing in the REPL
    anon[i] = () -> (println(i); i += 1; nothing)
    i += 1
end
anon[1]()
anon[1]()
anon[1]()
anon[1]()
anon[1]()

anon[2]()
anon[2]()

```

You would get

```julia
2
3
4
5
6
3
4

```

If you want something that really is surprising, you should check that closures are able to capture not-yet-defined variables of the scope in which they are defined.

```julia
anon = Array{Any}(undef, 2)
for i = 1:2
    anon[i] = () -> println(x)
    x = i * 2
end
anon[1]()
anon[2]()

```

gives

```julia
2
4

```

But at least:

```julia
anon = Array{Any}(undef, 2)
for i = 1:2
    anon[i] = () -> println(x)
    anon[i]()
    x = i * 2
end

```

Gives

```julia
ERROR: UndefVarError: x not defined

```

In the second example you give, I do not really agree the behaviour is surprising:

```julia
anon = Array{Any}(undef, 2)
let
    local i
    for outer i = 1:2
        anon[i] = ()-> println(i)
        i += 1
    end
end
anon[1]()
anon[2]()

```

Giving

```julia
3
3

```

Makes complete sense to me. `i` is not a binding of the inner scope, it is a binding of the **outer** scope (as the keyword indicates) so there is only one of it, and it is shared among all iterations. The for loop do not declare a new binding `i` each iteration but just **attributes the correct value** to the `i` already available. Note that the `for` do not just _increase_ `i`, otherwise the second iteration could end up being skipped, it does attribute to `i` the right value each iteration. In the example below, `anon[2]` would not be defined if it did not work this way:

```julia
anon = Array{Any}(undef, 2)
let
    local i
    for outer i = 1:2
        anon[i] = ()-> println(i)
        i = 20
    end
end

anon

```

Gives

```julia
2-element Array{Any,1}:
 var"#3#4"(Core.Box(20))
 var"#3#4"(Core.Box(20))

```

This kinda kills [my argument there are no boxes in Julia](https://discourse.julialang.org/t/is-it-appropriate-to-say-a-variable-is-a-label-or-box/46068/19) 😅 😆.

Finally, as I said before, all closures are capturing and sharing the same binding, what can be checked by:

```julia
anon = Array{Any}(undef, 2)
let
    local i
    for outer i = 1:2
        # the nothing below is just to avoid extra printing in the REPL
        anon[i] = ()-> (println(i); i *= 2; nothing)
    end
end
anon[1]()
anon[2]()
anon[1]()
anon[2]()
anon[1]()
anon[2]()

```

Which gives:

```julia
2
4
8
16
32
64

```

[Previous page](https://discourse.julialang.org/t/i-thought-i-understood-pass-by-sharing-in-julia-until-i-found-this/46897.md?page=1)
