Mutating function works in REPL but has no effect in tests

Arrays and References are pointers to mutable data, so even when the pointer is stored in a struct, the stored values can be modified.

When you want to control the creation of composite types to maintain invariants or provide defaults, Inner Constructors are handy.

Julia has atomic intrinsics that enforce thread-safe access.

I think what went wrong with the test is that @async starts a new task to go increment the value, but you never wait for that task to complete. So, in the REPL, enough time passed between lines for the task to finish, but during test was scheduled after the comparison.

Try this

using Test

abstract type Metric end

struct Gauge <: Metric
    name::String
    # A thread-safe reference to a Float64
    value::Threads.Atomic{Float64}
    # An inner constructor with a default value. 
    Gauge(name, initial=0.0) = new(name, Threads.Atomic{Float64}(initial))
end

function inc(metric::Metric, amount::Float64=1.0)
    # safe modification of the atomic reference
    Threads.atomic_add!(metric.value, amount)
    return nothing
end

function get(metric::Metric)
    metric.value[]
end

@testset "Gauge inc" begin
    g = Gauge("test")
    inc(g)
    @test get(g) == 1.0
end
1 Like