jw3126 / Setfield.jl

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

Modify array of immutables in place #134

Open non-Jedi opened 4 years ago

non-Jedi commented 4 years ago

If I have an array of immutable datastructures, it would be extremely advantageous from a performance perspective to be able to mutate that array in place instead of replacing it. The @set and @set! macros don't currently support this.

julia> using Setfield

julia> x = [(a=rand(), b=rand()) for _=1:2]
2-element Array{NamedTuple{(:a, :b),Tuple{Float64,Float64}},1}:
 (a = 0.13871066644823227, b = 0.12386194648118187)
 (a = 0.46679798730440436, b = 0.6032333077678709)

julia> y = x;

julia> @set! x[1].a = 0.0
2-element Array{NamedTuple{(:a, :b),Tuple{Float64,Float64}},1}:
 (a = 0.0, b = 0.12386194648118187)
 (a = 0.46679798730440436, b = 0.6032333077678709)

julia> y
2-element Array{NamedTuple{(:a, :b),Tuple{Float64,Float64}},1}:
 (a = 0.13871066644823227, b = 0.12386194648118187)
 (a = 0.46679798730440436, b = 0.6032333077678709)

Any ideas on supporting this use-case?

EDIT: possible duplicate of #32

EDIT2: and possibly solved by the macro definitions in the examples folder? Is there a reason those are an example rather than an exported part of Setfield.jl's public api?

jw3126 commented 4 years ago

Yes. So I think the main ingredients to support this do exist. There needs glue code to be written and probably some polishing, packaging and design decisions. I think what you want is an @set!! (and @lens!!) macro with "BangBang" semantics. That is it mutates if possible and copies if not. Roughly one needs to take the example you linked and replace e.g. Base.setindex! by BangBang.setindex!! etc. If you are interested in working on this, I am happy to help/review/give feedback etc.

jw3126 commented 4 years ago

The reason this does not already exist is probably that it requires Setfield to depend on BangBang (which currently depends on Setfield) and also that I have no pressing need for this feature.

tkf commented 4 years ago

Note that BangBang.jl has the widening semantics. So it's also possible to come up with an alternative @set-like interface that always mutates mutable data structure. Doing this in BangBang.jl is not appropriate because that's not its purpose. But I think BangBang.jl's internal trait system is handy when implementing this. I can extract out it as a package if people want to use it to implement their own @set.