Edit: See my first reply below for a more correct MWE.
Consider a struct
like
mutable struct Test
a::Int
end
After t = Test(1)
I would like to “bind” to the field so that after
x = t.a
t.a = 2
x
will evaluate as 2
. Is there any way to achieve that?
Context: I have a struct
that is only partially initialized during the time that I need to access it (using getproperty(mystruct, :myfield
) and “reference” the accessed field in another struct
. Some time later I am using that “reference”, after the accessed struct
is fully initialized.
Ok, I just noticed that this MWE is in fact not entirely related to my problem, since the Int
field is not mutable. What I am really looking at is taking a struct
like
import JuMP
mutable struct MyStruct
myfield::Union{JuMP.VariableRef, Nothing}
end
t = MyStruct(nothing)
x = getfield(t, :myfield)
t.myfield = JuMP.@variable(m)
So essentially I would like to keep a “binding” to a field that is of a mutable type, but is - at the time of binding - still nothing
.
There is a PR for that, but it’s not possible out of the box right now. You might be able to roll your own, e.g. copying the relevant bits from this PR:
import Base: RefValue, getindex, setindex!, isassigned, fieldindex
struct RefField{f,T,S} <: Ref{T}
x::RefValue{S}
RefField{f,T,S}(x::S) where {f,T,S} = new{f::Int,T,S}(RefValue(x))
end
RefField(x, f::Int) = RefField{f, fieldtype(typeof(x), f), typeof(x)}(x)
RefField(x, f::Symbol) = RefField(x, fieldindex(typeof(x), f))
getindex(b::RefField{f}) where {f} = getfield(b.x[], f)
setindex!(b::RefField{f,T}, x) where {f,T} = (setfield!(b.x[], f, convert(T, x)); b)
isassigned(b::RefField{f}) where {f} = isdefined(b.x[], f)
mutable struct T
a::Int
end
t = T(1)
x = RefField(t, :a)
t.a = 2
@show x[] # 2
Maybe a package doing this already exists?
2 Likes
Thanks, that solves it for me!
1 Like