Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set multiple fields at once in some sort of pipe? #15

Open
pdeffebach opened this issue Dec 11, 2020 · 7 comments
Open

Set multiple fields at once in some sort of pipe? #15

pdeffebach opened this issue Dec 11, 2020 · 7 comments

Comments

@pdeffebach
Copy link

It would be nice to be able to do

n = (a = 1, b  = 2, c = 3)
n2 = @set n begin 
    a = 4
    b = 100
end
@jw3126
Copy link
Member

jw3126 commented Dec 11, 2020

Yes, would be nice to have this, see also jw3126/Setfield.jl#80

@aplavin
Copy link
Collaborator

aplavin commented Nov 19, 2022

This is already (partially) supported, by the way:

julia> @set n[(:a, :b)] = (4, 100)
(a = 4, b = 100, c = 3)

Also see setall(), but that goes without syntactic sugar.

@wolthom
Copy link

wolthom commented Dec 26, 2022

Also just stumbled over this. Has there been any work on this feature?

@jw3126
Copy link
Member

jw3126 commented Dec 26, 2022

Not really, for me personally setproperties is almost always good enough.

@aplavin
Copy link
Collaborator

aplavin commented Dec 27, 2022

Agree, setproperties turns out to be enough more often than I originally expected :)
Sometimes I need to set multiple properties/indices in a nested structure (so setproperties isn't most convenient), but then it basically always is a (named)tuple - so @set n[(:a, :b)] = (4, 100) works.

Aside from the potential implementation itself, it's not obvious what the general interface should look like. Stuff like "set x.a, x.a.c.d, and x.b.c", or "set f(x).b, g(x.a) and h(x.a).b" within a single operation. Is it even possible to make easy and convenient?

@aplavin
Copy link
Collaborator

aplavin commented Apr 23, 2023

Depending on the specific usecase, a recent feature of AccessorsExtra can be useful:

julia> o = @optic₊ (_.a, _.b)

julia> set(n, o, (4, 100))
(a = 4, b = 100, c = 3)

Isn't much of a win for single-use (is it even possible to make shorter syntax?), but can help when reusing the optic in multiple occasions.

@aplavin
Copy link
Collaborator

aplavin commented Feb 28, 2024

This seems to be the oldest open issue on the topic, best to consolidate any potential discussion in one place. Others are #119 and #82.

A rough summary of the current understanding:

  • Would be useful to have the ability to set/update several optics at once, and still have the target object constructed only once (not N times = number of optics).
  • This is challenging to implement generically, aside from the most basic cases already covered by setproperties. See also Kaleido.jl for earlier attempts to do that based on Setfields.jl.

More practically, for now:

  • If you want an optic to refer to several parts of the object, use optic ++ optic ++ ... or @optics ... from AccessorsExtra.jl. Setting it (with setall()) reconstructs the object multiple times, but should be free/cheap for small structs. This is used in packages like PlutoTables and AccessibleOptimization, can be upstreamed into Accessors proper within a reasonable time frame.
  • Closer to the original topic of this issue, "Set multiple fields at once in some sort of pipe" – there are already convenient piping solutions orthogonal to Accessors
    ([Feature request] Set multiple fields at once #119 (comment)):
julia> using Accessors, DataPipes

julia> nt = (a=1, b=2)

julia> @p let
       nt
       @set __.b = 3
       @set __.a += 4
       @insert __.c = 9
       @set (last(__)) += 1
   end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants