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:
#!/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”!
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:
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()
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.)
Thanks for taking time… here is my output from bash; I tested on Windows WSL and on macOS:
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
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> 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).