jw3126 / Setfield.jl

Update deeply nested immutable structs.
Other
167 stars 17 forks source link

Updating more than one field at a time #62

Closed BenjaminBorn closed 5 years ago

BenjaminBorn commented 5 years ago

Thanks for this very helpful package! I often want to update more than one field in a structure at the same time. Is this somehow possible with this package? I tried

using Setfield

struct B
   x::Int
   y::Float64
   z::Bool
end

b = B(1, 2.4, false)

@set b.y, b.z = 2.1, true

but that doesn't work.

If it's not possible yet, would you consider adding such a feature in some form?

Edit: Somewhat unrelated but I just found @set!. Should I rather use that than @set when replacing values in an existing structure?

jw3126 commented 5 years ago

Updating multiple values of an object at the same time is currently not possible with @set. A lot of people including myself want it. The problem is that somebody actually has to implement it :smile:.

While not as good as versatile as the @set macro itself, there is setproperties:

julia> using Setfield: setproperties

julia> setproperties(b, (y=2.1, z=true))
B(1, 2.1, true)

Concerning your other question

@set! b.y = 2.1

and

b = @set b.y = 2.1

are equivalent, so yes I would use @set! for replacing existing values.

BenjaminBorn commented 5 years ago

Thank you very much for the quick reply. setproperties is already very helpful!

singularitti commented 5 years ago

@BenjaminBorn FYI, I think what you were asking exists now. Have a look at Kaleido.jl, as mentioned in #74.

jw3126 commented 5 years ago

@singularitti Are you sure? I think there is @batchlens, but not @batchset?

tkf commented 5 years ago

but not @batchset

Right, ATM Kaleido.jl is only for creating lenses and no @set-like macros.

singularitti commented 5 years ago

but not @batchset

Right, ATM Kaleido.jl is only for creating lenses and no @set-like macros.

Correct me if I am wrong. But isn't it the set statement in your example semantically equivalent to the @set b.y, b.z = 2.1, true?

julia> using Setfield, Kaleido

julia> lens_batch = @batchlens begin
           _.a.b.c
           _.a.b.d[1]
           _.a.b.d[3] ∘ settingas𝕀
           _.a.e
       end;

julia> obj = (a = (b = (c = 1, d = (2, 3, 0.5)), e = 5),);

julia> get(obj, lens_batch)
(1, 2, 0.0, 5)

julia> set(obj, lens_batch, (10, 20, Inf, 50))
(a = (b = (c = 10, d = (20, 3, 1.0)), e = 50),)
tkf commented 5 years ago

What I meant was that Kaleido does not have something like:

obj2 = @batchset begin
    obj.a.b.c = 10
    obj.a.b.d[1] = 20
    obj.a.b.d[3] ∘ settingas𝕀 = Inf
    obj.a.e = 50
end

You are right that the combination of @batchlens and set function is semantically equivalent to this. I was just pointing out a handy shortcut is missing.