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

[Feature request] Set multiple fields at once #119

Closed
Vilin97 opened this issue Oct 5, 2023 · 6 comments
Closed

[Feature request] Set multiple fields at once #119

Vilin97 opened this issue Oct 5, 2023 · 6 comments

Comments

@Vilin97
Copy link

Vilin97 commented Oct 5, 2023

Setting several fields at once would reduce the number of times the immutable struct is copied. For example,

nt = (a=1, b=2)
@reset nt.a=2, nt.b=3

instead of

nt = (a=1, b=2)
@reset nt.a=2
@reset nt.b=3
@aplavin
Copy link
Member

aplavin commented Oct 5, 2023

Are you mostly looking for performance or convenience? If the former, then "copying immutable struct" should be free in most cases:

julia> nt = (a=1, b=2, c=3)
julia> @btime let
       x = @set $nt.a = 10
       y = @set x.b = 20
       end
  1.333 ns (0 allocations: 0 bytes)
(a = 10, b = 20, c = 3)

If convenience, then:

  • For setting properties at the top level, there's setproperties(nt, (a=10, b=20)).
  • Setting arbitrary optics at once would be useful and there are multiple related features requests, see eg "Concat lens": combine multiple lenses side by side #82. But implementing it so that the operation is really done with a single call when possible is complicated, and the proper interface is not obvious.

@Vilin97
Copy link
Author

Vilin97 commented Oct 5, 2023

I am mostly looking for performance.
How can constructing a new struct be free? If a struct has n fields, how can creating a new struct not be O(n) time?

@aplavin
Copy link
Member

aplavin commented Oct 6, 2023

Often, immutable structs are not really "created" in this sense, they don't physically exist in memory.

@ronisbr
Copy link

ronisbr commented Feb 10, 2024

Yes! I can confirm @aplavin statement. In all cases I used Accessors.jl, I saw no performance penalty by setting multiple parameters at once with ConstructionBase.setproperties ou using multiple @resets. However, I think something like this would be less verbose:

@resets nt begin
    nt.a = 1
    nt.b = 2
    nt.c = 3
    ....
end

This idea is to replace all expressions with nt.a to @reset nt.a inside this block.

@aplavin
Copy link
Member

aplavin commented Feb 10, 2024

That's how I tend to write sequences of Accessors (or any other!) operations:

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
(a = 5, b = 3, c = 16.0)

# or as a part of a larger pipeline:
julia> nts = [nt, nt]

julia> @p let
       nts
       map() do __
           @insert __.c = 9
           @set __.a += 4
       end
   end
2-element Vector{@NamedTuple{a::Int64, b::Int64, c::Int64}}:
 (a = 5, b = 2, c = 9)
 (a = 5, b = 2, c = 9)

Looking at these examples, not sure if the @resets macro from your example would noticeably improve them...
These flexible building blocks really play nicely together in Julia! :)

@aplavin
Copy link
Member

aplavin commented Feb 28, 2024

Closing as duplicate of #15

@aplavin aplavin closed this as completed Feb 28, 2024
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

3 participants