Copy of immutable with multiple fields changed

Is there a package which makes it convenient to get a copy of an (immutable) struct with new values for some fields? I am aware of Setfield, but my understanding (see below) is that it requires nesting to do this.

using Setfield

struct Foo
    a
    b
    c
end

x = Foo(1, 2, 3)
y = @set (@set x.a = 'a').b = 'b' # making this simpler?

I am also looking for such a package. Right now i am using Parameters.jl wich allows for this

using Parameters

@with_kw struct Foo
   a
   b
   c
end

x = Foo(1,  2,  3)
y = Foo(x, a='a', b='b')
1 Like

This is a simplified version of my set function which takes a single argument. It can be extended for a tuple:

function set(str,var,val)
    !any(i->i==var, fieldnames(typeof(str))) && @warn "\n No field in struct $(typeof(str)) is named $(var)!\n Fields are $(fieldnames(typeof(str)))"
    dict = Dict{Symbol,Any}()
    for name in fieldnames(typeof(str))
        if name == var
            dict[name] = val
        else
            dict[name] = getfield(str,name)
        end
    end
    x = NamedTuple{Tuple(keys(dict))}(values(dict))
    str = typeof(str)(x...)
end

E.g.:

struct Foo
    a
    b
    c
end

x = Foo(1, 2, 3)

y = set(x, :a, 5)

julia> y
Foo(5, 2, 3)

There must be more efficient ways to deal with this with macros as in Setfield.jl but I don’t use it in performance-critical parts of the code so it works for me.

1 Like

Setfield exports the function setproperites which allows you to set multiple fields in one call with a namedtuple:

julia> using Setfield

julia> struct A;a;b;c;end

julia> a = A(1,2,3)
A(1, 2, 3)

julia> setproperties(a, (b=5, c=7))
A(1, 5, 7)
4 Likes