How can I "flag" that I mutated a field in a struct such as a vector

Suppose I have a struct where I am mutating one of the fields (say it is a Vector) like

struct A
    x::Vector
end

a = A([1, 2])
a.x[1] = 0

and I want to have some sort of flag to indicate whether I have mutated a.x. How can I do this? Currently, I am doing

struct A
    x::Vector
    flag::Vector{Bool}
end

where A.flag is just a 1-element vector so that it is mutable and I can update it. I’m sure this is not the best way to do this.

I am aware of Accessors.jl, but I don’t want to copy/construct a new object when I update. I also looked at Observables.jl, but the docs are sparse and it is not obvious to me how I would implement this. Any ideas and help is appreciated!

Here is one approach.

julia> struct A{T}
           x::Vector{T}
           flag::Base.RefValue{Bool}
           A(v) = new{eltype(v)}(v, Ref(false))
       end

julia> a = A([1,2])
A{Int64}([1, 2], Base.RefValue{Bool}(false))

julia> a.x[1] = 2
2

julia> a.flag[] = true
true

julia> a
A{Int64}([2, 2], Base.RefValue{Bool}(true))

I parameterized the struct A with T so that x will have a concrete type Vector{T}. x::Vector by itself is an abstract type and is not very compiler friendly.

Ref is basically a 0-dimensional array with one element. It is slightly more space efficient than your version. Here I used Base.RefValue since it is a concrete type while Ref is an abstract type.

I might go further and implement Base.setindex! for your new type. Here you can do an indexed assignment on a directly, and this will be forwarded to modify the field x. While doing so, it will set the flag.

julia> function Base.setindex!(A, X, inds...)
           setindex!(A.x, X, inds...)
           A.flag[] = true
       end

julia> a = A([1,2])
A{Int64}([1, 2], Base.RefValue{Bool}(false))

julia> a[1] = 3
3

julia> a
A{Int64}([3, 2], Base.RefValue{Bool}(true))
2 Likes

Exactly what I was looking for, thank you!