In Julia, how to create a function that saves its own internal state?

If I benchmarked everything correctly, the functor with the pure-Int field is by far more efficient. Followed by the functor with the Union{Nothing,Int} field:

julia> include("state.jl")
let:  3.595 μs (0 allocations: 0 bytes)
# functor with `Any` field
f1:  29.342 μs (1000 allocations: 15.62 KiB)
f1_const:  28.184 μs (1000 allocations: 15.62 KiB)
# functor with Union field:
f2:  1.260 μs (0 allocations: 0 bytes)
f2_const:  1.259 μs (0 allocations: 0 bytes)
# functor with pure Int field
f3:  257.421 ns (0 allocations: 0 bytes)
f3_const:  257.424 ns (0 allocations: 0 bytes)
Code

let state = Ref{Union{Int, Nothing}}(nothing)
    global f
    function f()
        if state[] !== nothing
            state[] += 1
        else
            state[] = 1
        end
        state[]
    end
end

Base.@kwdef mutable struct F1
  state = nothing
end

function (o::F1)()
  if o.state == nothing
    o.state = 1
  else
    o.state += 1
  end
end

f1 = F1()
const f1_const = F1()

Base.@kwdef mutable struct F2
  state::Union{Nothing,Int} = nothing
end

function (o::F2)()
  if o.state == nothing
    o.state = 1
  else
    o.state += 1
  end
end

f2 = F2()
const f2_const = F2()

Base.@kwdef mutable struct F3
  state::Int = 0
end

function (o::F3)()
  if o.state == 0
    o.state = 1
  else
    o.state += 1
  end
end

f3 = F3()
const f3_const = F3()

function update_state!(f,n) 
  for i in 1:n
    f()
  end
end


using BenchmarkTools
n = 1000
print("let:"); @btime update_state!($f,$n)
print("f1:"); @btime update_state!($f1,$n)
print("f1_const:"); @btime update_state!($f1_const,$n)
print("f2:"); @btime update_state!($f2,$n)
print("f2_const:"); @btime update_state!($f2_const,$n)
print("f3:"); @btime update_state!($f3,$n)
print("f3_const:"); @btime update_state!($f3_const,$n)

7 Likes