# Mutating function works in REPL but has no effect in tests

**URL:** <https://discourse.julialang.org/t/mutating-function-works-in-repl-but-has-no-effect-in-tests/50728>\
**Category:** New to Julia\
**Created:** [November 25, 2020, 4:35am UTC](https://discourse.julialang.org/t/mutating-function-works-in-repl-but-has-no-effect-in-tests/50728 "2020-11-25T04:35:42Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![mdneuzerling](https://avatars.discourse-cdn.com/v4/letter/m/ccd318/32.png) [@mdneuzerling](https://discourse.julialang.org/u/mdneuzerling)\
**Post date:** [November 25, 2020, 4:35am UTC](https://discourse.julialang.org/t/mutating-function-works-in-repl-but-has-no-effect-in-tests/50728/1 "2020-11-25T04:35:42Z")

</div>

Hi folks,

I thought I’d see how far I could get at creating a [Prometheus client](https://prometheus.io/docs/instrumenting/writing_clientlibs/) for Julia, to cut my teeth and learn about package development. This involves juggling stateful objects (metrics) which are mutated in place. I’ve got the [very beginnings of a repo here](https://github.com/mdneuzerling/PrometheusClient/tree/d19e361e48c1b90ae89e15101396fce40bb889ebt) but the stripped-down core idea is below:

```julia
mutable struct MetricValue
    value::Float64
    lock::ReentrantLock
end

abstract type Metric end

mutable struct Gauge <: Metric
    name::String
    value::MetricValue
end

function inc(metric::Metric, amount::Real = 1.0)
    @async begin
        lock(metric.value.lock)
        metric.value.value = metric.value.value + amount
        unlock(metric.value.lock)
    end
    return nothing
end

function get(metric::Metric)
    lock(metric.value.lock)
    current_value = metric.value.value
    unlock(metric.value.lock)
    current_value
end

function Gauge(name::String; value::Real = 0)
    Gauge(name, MetricValue(value))
end

```

Now, the following code snippet works just fine in a repl:

```julia
using Test
g = Gauge("test") # initialised with a value of 0
inc(g)
@test get(g) == 1.0

```

But when I try to place this snippet in a test (as commented out in my repository) I get entirely different behaviour: the `inc(g)` has no effect at all, and the value of `g` stays at its initial value of 0.0.

Normally I’d attribute this to my lack of understanding of how scoping works in Julia, but the fact that everything is okay in a REPL really throws me off here. Do you know what I might be doing wrong?

Additionally, have I handled the `@async` and `lock` stuff as I should have? The idea I was going for is to do all metric updating asynchronously, but if two attempts to manipulate a single metric clash then the second one has to wait its turn.

```nohighlight
Julia Version 1.5.0
Commit 96786e22cc (2020-08-01 23:44 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Core(TM) i7-7500U CPU @ 2.70GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-9.0.1 (ORCJIT, skylake)

```

---

<div class="post-metadata">

**Author:** ![contradict](https://avatars.discourse-cdn.com/v4/letter/c/ac91a4/32.png) [@contradict](https://discourse.julialang.org/u/contradict)\
**Post date:** [November 25, 2020, 5:21am UTC](https://discourse.julialang.org/t/mutating-function-works-in-repl-but-has-no-effect-in-tests/50728/2 "2020-11-25T05:21:21Z")

</div>

[Arrays](https://docs.julialang.org/en/v1/manual/arrays/) and [References](https://docs.julialang.org/en/v1/base/c/#Core.Ref) 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](https://docs.julialang.org/en/v1/manual/constructors/#man-inner-constructor-methods) are handy.

Julia has [atomic intrinsics](https://docs.julialang.org/en/v1/base/multi-threading/#Atomic-operations) 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

```julia
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

```

---

<div class="post-metadata">

**Author:** ![mdneuzerling](https://avatars.discourse-cdn.com/v4/letter/m/ccd318/32.png) [@mdneuzerling](https://discourse.julialang.org/u/mdneuzerling)\
**Post date:** [November 25, 2020, 5:56am UTC](https://discourse.julialang.org/t/mutating-function-works-in-repl-but-has-no-effect-in-tests/50728/3 "2020-11-25T05:56:29Z")

</div>

Of course it’s the async! Concurrent programming is a big weakness of mine. Thank you so much!

The inbuilt atomics look to be a lot simpler, although I was very proud of what I thought were my functioning locks. It seems I have a lot to learn about this stuff.
