Hello,
I’ve been poring over docs for Accessors.jl, Setfield.jl, Parameters.jl, and Discourse, and haven’t found a clear answer to this question.
The problem I would like to solve is expressed by this MWE:
struct ParamObj
a
b
c
end
function new_params(x, y)
return (a=x, b=y)
end
po = ParamObj(1.0, 2.0, 3.0)
nt = new_params(4.0, 5.0)
po2 = nt_into_struct(po, nt)
# ParamObj(4.0, 5.0, 3.0)
where this imaginary function nt_into_struct
takes all the fields of the NamedTuple and, a la Accessors.jl, produces a new instance where fields not in the NamedTuple come from the base object. Key here is that I may have several different functions producing these NamedTuples, which (I think) are each inferrable themselves but map to different fields of the struct, so I would like to programmatically assess which fields need to be set.
The best I could produce myself, using Accessors, is
function nt_into_struct(po, nt::NamedTuple)
@warn "Copying arbitrary NamedTuple into struct. Type unstable. If doing this repeatedly, define a new method for copy_nt_into_struct" nt
po_new = deepcopy(po)
for (k, v) in zip(keys(nt), values(nt))
po_new = set(po_new, PropertyLens{k}(), v)
end
return po_new
end
which does the job but is type-unstable, which is not acceptable for me since this is going to be in a hot inner loop.
I can write new methods like
function nt_into_struct(po, nt::NamedTuple{(:a, :b)})
po_new = deepcopy(po)
@reset po_new.a = nt.a
@reset po_new.b = nt.b
return po_new
end
but then I have to write each of these methods manually; I can deal with that but feel like there ought to be a more elegant solution, especially since this will be specific to the ordering of parameters in the NamedTuple.
I can imagine a macro that generates new methods of nt_into_struct
like this, but don’t feel confident enough to have tried that yet.
A function like reconstruct, which allows reconstruct(po; nt...)
from Parameters.jl would do the trick, but the docs there warn that it is slow and to look at Setfield.jl.
I have the feeling that I am missing something obvious here (like maybe all my structs here should just be NamedTuples, in which case I can use merge
.)