# Odd behavior with closures and let block (inside script)

**URL:** <https://discourse.julialang.org/t/odd-behavior-with-closures-and-let-block-inside-script/114007>\
**Category:** New to Julia\
**Created:** [May 8, 2024, 3:40pm UTC](https://discourse.julialang.org/t/odd-behavior-with-closures-and-let-block-inside-script/114007 "2024-05-08T15:40:44Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![martin.auer](https://avatars.discourse-cdn.com/v4/letter/m/f19dbf/32.png) [@martin.auer](https://discourse.julialang.org/u/martin.auer)\
**Post date:** [May 8, 2024, 3:40pm UTC](https://discourse.julialang.org/t/odd-behavior-with-closures-and-let-block-inside-script/114007/1 "2024-05-08T15:40:44Z")

</div>

Hi,

I try to hide some state in a let block, as in [Does Julia Need a C++ style `static` keyword? - #4 by antoine-levitt](https://discourse.julialang.org/t/does-julia-need-a-c-style-static-keyword/29176/4) (In particular, I don’t want it in the module scope.)

Here are 3 variants of a counter given in script-form – the first uses an Int; the 2nd and 3rd hide the Int inside a mutable struct:

```julia
#!/usr/bin/env julia

module Minex1
    let
        i::Int64 = 0

        global get_i() = i
        global inc_i() = ( i += 1 )
    end
end

module Minex2
    let
        mutable struct S i::Int64 end
        s::S = S(0)

        global get_i() = s.i
        global inc_i() = ( s.i += 1 )
    end
end

module Minex3
    let
        mutable struct S i::Int64 end
        s::S = S(0)

        global get_i() = ( tmp="$(s.i)"; s.i )
        global inc_i() = ( s.i += 1 )
    end
end

function main()
    print(Minex1.get_i()); Minex1.inc_i(); println(Minex1.get_i())
    print(Minex2.get_i()); Minex2.inc_i(); println(Minex2.get_i())
    print(Minex3.get_i()); Minex3.inc_i(); println(Minex3.get_i())
end
if abspath(PROGRAM_FILE) == @ __FILE__
    main()  
end

```

Variant Minex1 (1st line in main) gives “01” as expected.  
Minex2 weirdly yields “00” – this I don’t get.  
Minex3 yields “01” again!

On top – in the REPL, all 3 lines of main output “01”!

Am a bit lost; any help/idea greatly appreciated!

---

<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 8, 2024, 4:21pm UTC](https://discourse.julialang.org/t/odd-behavior-with-closures-and-let-block-inside-script/114007/2 "2024-05-08T16:21:53Z")

</div>

> [@martin.auer](#):
>
> Minex2 weirdly yields “00” – this I don’t get.

Why not, isn’t that expected from the definition of `get_i()` inside `Minex2`?

~~Apart from that, since you are modifying the definition of global functions multiple times, confusing things certainly can happen, dependent on the order of evaluation of the code. Best is to avoid that.~~

 

~~Are you actually using such a pattern or is this an exercise?~~

ps: I think it is more clear if you print like this:

```julia
function main()
    @show Minex1.get_i(), Minex1.inc_i(), Minex1.get_i()
    @show Minex2.get_i(), Minex2.inc_i(), Minex2.get_i()
    @show Minex3.get_i(), Minex3.inc_i(), Minex3.get_i()
end

main()

```

resulting in:

```julia
(Minex1.get_i(), Minex1.inc_i(), Minex1.get_i()) = (0, 1, 1)
(Minex2.get_i(), Minex2.inc_i(), Minex2.get_i()) = (0, 1, 1)
(Minex3.get_i(), Minex3.inc_i(), Minex3.get_i()) = (0, 1, 1)

```

(seems consistent to me at first sight)

---

<div class="post-metadata">

**Author:** ![martin.auer](https://avatars.discourse-cdn.com/v4/letter/m/f19dbf/32.png) [@martin.auer](https://discourse.julialang.org/u/martin.auer)\
**Post date:** [May 8, 2024, 4:26pm UTC](https://discourse.julialang.org/t/odd-behavior-with-closures-and-let-block-inside-script/114007/3 "2024-05-08T16:26:52Z")

</div>

Well, REPL yields the expected 01, ie, the increase works. When executing as script, however, it does not – except when, in case 3, I use a string interpolation…

I think the functions being “global” here just puts them from the let block inside the enclosing Module, so they should not clash.

(And yes, I would like to implement the pattern suggested in the link I mentioned at the beginning.)

---

<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 8, 2024, 4:28pm UTC](https://discourse.julialang.org/t/odd-behavior-with-closures-and-let-block-inside-script/114007/4 "2024-05-08T16:28:14Z")

</div>

I don´t see any difference in the REPL behavir vs script, by the way (not with your original version or the other show function I used there).

---

<div class="post-metadata">

**Author:** ![martin.auer](https://avatars.discourse-cdn.com/v4/letter/m/f19dbf/32.png) [@martin.auer](https://discourse.julialang.org/u/martin.auer)\
**Post date:** [May 8, 2024, 4:32pm UTC](https://discourse.julialang.org/t/odd-behavior-with-closures-and-let-block-inside-script/114007/5 "2024-05-08T16:32:03Z")

</div>

Thanks for taking time… here is my output from bash; I tested on Windows WSL and on macOS:

```julia
DEV_julia_let_block/$ julia --version
julia version 1.9.2
DEV_julia_let_block/$ cat test.jl
#!/usr/bin/env julia

module Minex1
    let
        i::Int64 = 0

        global get_i() = i
        global inc_i() = ( i += 1 )
    end
end

module Minex2
    let
        mutable struct S i::Int64 end
        s::S = S(0)

        global get_i() = s.i
        global inc_i() = ( s.i += 1 )
    end
end

module Minex3
    let
        mutable struct S i::Int64 end
        s::S = S(0)

        global get_i() = ( tmp="$(s.i)"; s.i )
        global inc_i() = ( s.i += 1 )
    end
end

function main()
    print(Minex1.get_i()); Minex1.inc_i(); println(Minex1.get_i())
    print(Minex2.get_i()); Minex2.inc_i(); println(Minex2.get_i())
    print(Minex3.get_i()); Minex3.inc_i(); println(Minex3.get_i())
end
if abspath(PROGRAM_FILE) == @ __FILE__
    main()
end

DEV_julia_let_block/$ julia test.jl
01
00
01

```

---

<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 8, 2024, 4:34pm UTC](https://discourse.julialang.org/t/odd-behavior-with-closures-and-let-block-inside-script/114007/6 "2024-05-08T16:34:37Z")

</div>

Uhm, that’s not what I get:

```julia
~/Downloads% julia test2.jl 
01
01
01

```

---

<div class="post-metadata">

**Author:** ![martin.auer](https://avatars.discourse-cdn.com/v4/letter/m/f19dbf/32.png) [@martin.auer](https://discourse.julialang.org/u/martin.auer)\
**Post date:** [May 8, 2024, 4:35pm UTC](https://discourse.julialang.org/t/odd-behavior-with-closures-and-let-block-inside-script/114007/7 "2024-05-08T16:35:44Z")

</div>

Could you please tell me your Julia version?

---

<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 8, 2024, 4:40pm UTC](https://discourse.julialang.org/t/odd-behavior-with-closures-and-let-block-inside-script/114007/8 "2024-05-08T16:40:26Z")

</div>

It is 1.10.3, and indeed, the result differs from 1.9.2:

```julia
~/Downloads% julia +release --startup-file=no test2.jl 
01
01
01
~/Downloads% julia +1.9.2 --startup-file=no test2.jl
01
00
01

```

---

<div class="post-metadata">

**Author:** ![adienes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/adienes/32/37459_2.png) [@adienes](https://discourse.julialang.org/u/adienes)\
**Post date:** [May 8, 2024, 4:42pm UTC](https://discourse.julialang.org/t/odd-behavior-with-closures-and-let-block-inside-script/114007/9 "2024-05-08T16:42:13Z")

</div>

I believe there is a bug on all `1.9.x` versions causing this. the behavior seems fine on all versions `<1.9.0` and `>= 1.10.0`

---

<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 8, 2024, 4:57pm UTC](https://discourse.julialang.org/t/odd-behavior-with-closures-and-let-block-inside-script/114007/10 "2024-05-08T16:57:58Z")

</div>

All that said, since this is “new to Julia” section, maybe it might be interesting to think about using functors, if you want to have a state-dependent function that can be updated:

```julia-repl
julia> mutable struct A
           i::Int
       end

julia> (a::A)(x) = x * a.i 

julia> a = A(1)
A(1)

julia> a(5)
5

julia> a.i += 1
2

julia> a
A(2)

julia> a(5)
10

```

(you can make a struct a _callable object_, that carries its state and behaves as a function).
