Mutable struct vs closure

(as illustrated in my previous example) we need several tricks to build “good” closure. Following your example:

julia> inc.x
Core.Box(6.6)
julia> getfield(inc, :x)
Core.Box(6.6)

the captured variable x is a Core.Box, which is bad.

Now, we need the following tricks:

  1. even for scalar, use Array (of length 1) to store captured variables.
  2. enclose the closure definition by local <closure_name>, let <captured_variable> = <captured_variable> and end
function closuremaker2()
    x = [1]   # trick 1: to avoid Core.Box, even scalar captured variable needs to be store in an Array

    local inc2   # trick 2
    let x = x    # trick 2
    function inc2()
        x[1] += 1    # trick 1
        x[1]     # trick 1
    end
    end    # trick 2

    inc2
end

julia> inc2 = closuremaker2()
inc2 (generic function with 1 method)

julia> inc2()
2

julia> inc2.x.contents=5.6
ERROR: type #inc2#5 has no field x

julia> inc2()
3

julia> ind2.x
ERROR: UndefVarError: ind2 not defined

julia> getfield(inc2, :x)
ERROR: type #inc2#5 has no field x

after using these tricks, the captured variable is completed encapsulated (as far as I know): it’s no longer a Core.Box, and could not be access directly, even with getfield().