Comments (14)
It's built on ConstructionBase.setproperties
that provides an efficient way to set multiple properties. Feel free to use that function!
from accessors.jl.
We use Accessors.jl a lot in SatelliteToolbox.jl ecosystem, which helped to increase the performance by a huge margin. It is just awesome.
In the past, I tested exactly this behavior. I am not very knowledgeable in compilers, but it seems that most of time the compiler can avoid creating those multiple objects inside the code. For example:
using Accessors
struct MyStruct
a::Int64
b::Int64
c::Int64
d::Int64
end
function modstruct1(s::MyStruct)
@reset s.a = 10
@reset s.d = 10
return s
end
function modstruct2(s::MyStruct)
s = Accessors.ConstructionBase.setproperties(s, (a = 10, d = 10))
return s
end
julia> modstruct1(MyStruct(1, 2, 3, 4))
MyStruct(10, 2, 3, 10)
julia> modstruct2(MyStruct(1, 2, 3, 4))
MyStruct(10, 2, 3, 10)
julia> @code_llvm modstruct1(MyStruct(1, 2, 3, 4))
; @ REPL[3]:1 within `modstruct1`
define void @julia_modstruct1_194([4 x i64]* noalias nocapture noundef nonnull sret([4 x i64]) align 8 dereferenceable(32) %0, [4 x i64]* nocapture noundef nonnull readonly align 8 dereferenceable(32) %1) #0 {
top:
; @ REPL[3]:2 within `modstruct1`
; ┌ @ /Users/ronan.arraes/.julia/packages/Accessors/hjkBO/src/optics.jl:375 within `set`
; │┌ @ /Users/ronan.arraes/.julia/packages/ConstructionBase/JFKjZ/src/ConstructionBase.jl:131 within `setproperties`
; ││┌ @ /Users/ronan.arraes/.julia/packages/ConstructionBase/JFKjZ/src/ConstructionBase.jl:213 within `setproperties_object`
; │││┌ @ /Users/ronan.arraes/.julia/packages/ConstructionBase/JFKjZ/src/ConstructionBase.jl:103 within `getproperties`
; ││││┌ @ broadcast.jl:903 within `materialize`
; │││││┌ @ broadcast.jl:1118 within `copy`
; ││││││┌ @ ntuple.jl:69 within `ntuple`
; │││││││┌ @ ntuple.jl:72 within `macro expansion`
; ││││││││┌ @ broadcast.jl:1118 within `#31`
; │││││││││┌ @ broadcast.jl:682 within `_broadcast_getindex`
; ││││││││││┌ @ broadcast.jl:709 within `_broadcast_getindex_evalf`
; │││││││││││┌ @ Base.jl:37 within `getproperty`
%memcpy_refined_src = getelementptr inbounds [4 x i64], [4 x i64]* %1, i64 0, i64 1
; └└└└└└└└└└└└
; @ REPL[3]:4 within `modstruct1`
%newstruct.sroa.0.0..sroa_idx = getelementptr inbounds [4 x i64], [4 x i64]* %0, i64 0, i64 0
store i64 10, i64* %newstruct.sroa.0.0..sroa_idx, align 8
%newstruct.sroa.2.0..sroa_idx5 = getelementptr inbounds [4 x i64], [4 x i64]* %0, i64 0, i64 1
; @ REPL[3]:3 within `modstruct1`
; ┌ @ /Users/ronan.arraes/.julia/packages/Accessors/hjkBO/src/optics.jl:375 within `set`
; │┌ @ /Users/ronan.arraes/.julia/packages/ConstructionBase/JFKjZ/src/ConstructionBase.jl:131 within `setproperties`
; ││┌ @ /Users/ronan.arraes/.julia/packages/ConstructionBase/JFKjZ/src/ConstructionBase.jl:217 within `setproperties_object`
; │││┌ @ REPL[2]:2 within `MyStruct`
%2 = bitcast i64* %memcpy_refined_src to <2 x i64>*
%3 = load <2 x i64>, <2 x i64>* %2, align 8
; └└└└
; @ REPL[3]:4 within `modstruct1`
%4 = bitcast i64* %newstruct.sroa.2.0..sroa_idx5 to <2 x i64>*
store <2 x i64> %3, <2 x i64>* %4, align 8
%newstruct.sroa.4.0..sroa_idx7 = getelementptr inbounds [4 x i64], [4 x i64]* %0, i64 0, i64 3
store i64 10, i64* %newstruct.sroa.4.0..sroa_idx7, align 8
ret void
}
julia> @code_llvm modstruct2(MyStruct(1, 2, 3, 4))
; @ REPL[4]:1 within `modstruct2`
define void @julia_modstruct2_208([4 x i64]* noalias nocapture noundef nonnull sret([4 x i64]) align 8 dereferenceable(32) %0, [4 x i64]* nocapture noundef nonnull readonly align 8 dereferenceable(32) %1) #0 {
top:
; @ REPL[4]:2 within `modstruct2`
; ┌ @ /Users/ronan.arraes/.julia/packages/ConstructionBase/JFKjZ/src/ConstructionBase.jl:131 within `setproperties`
; │┌ @ /Users/ronan.arraes/.julia/packages/ConstructionBase/JFKjZ/src/ConstructionBase.jl:213 within `setproperties_object`
; ││┌ @ /Users/ronan.arraes/.julia/packages/ConstructionBase/JFKjZ/src/ConstructionBase.jl:103 within `getproperties`
; │││┌ @ broadcast.jl:903 within `materialize`
; ││││┌ @ broadcast.jl:1118 within `copy`
; │││││┌ @ ntuple.jl:69 within `ntuple`
; ││││││┌ @ ntuple.jl:72 within `macro expansion`
; │││││││┌ @ broadcast.jl:1118 within `#31`
; ││││││││┌ @ broadcast.jl:682 within `_broadcast_getindex`
; │││││││││┌ @ broadcast.jl:709 within `_broadcast_getindex_evalf`
; ││││││││││┌ @ Base.jl:37 within `getproperty`
%memcpy_refined_src = getelementptr inbounds [4 x i64], [4 x i64]* %1, i64 0, i64 1
; └└└└└└└└└└└
; @ REPL[4]:3 within `modstruct2`
%newstruct.sroa.0.0..sroa_idx = getelementptr inbounds [4 x i64], [4 x i64]* %0, i64 0, i64 0
store i64 10, i64* %newstruct.sroa.0.0..sroa_idx, align 8
%newstruct.sroa.2.0..sroa_idx5 = getelementptr inbounds [4 x i64], [4 x i64]* %0, i64 0, i64 1
; @ REPL[4]:2 within `modstruct2`
; ┌ @ /Users/ronan.arraes/.julia/packages/ConstructionBase/JFKjZ/src/ConstructionBase.jl:131 within `setproperties`
; │┌ @ /Users/ronan.arraes/.julia/packages/ConstructionBase/JFKjZ/src/ConstructionBase.jl:217 within `setproperties_object`
; ││┌ @ REPL[2]:2 within `MyStruct`
%2 = bitcast i64* %memcpy_refined_src to <2 x i64>*
%3 = load <2 x i64>, <2 x i64>* %2, align 8
; └└└
; @ REPL[4]:3 within `modstruct2`
%4 = bitcast i64* %newstruct.sroa.2.0..sroa_idx5 to <2 x i64>*
store <2 x i64> %3, <2 x i64>* %4, align 8
%newstruct.sroa.4.0..sroa_idx7 = getelementptr inbounds [4 x i64], [4 x i64]* %0, i64 0, i64 3
store i64 10, i64* %newstruct.sroa.4.0..sroa_idx7, align 8
ret void
}
Again, I am no compiler expert, but it really seems to me that the compiler is using the same object to update the two values.
from accessors.jl.
First the problem was the LLVM output that was "huge", now it is the allegedly very high compile times (that Julia 1.10 is handling pretty well). So, Ok, do what you want. However, for everybody else that is reading this thread, just use Accessors.jl if you want to develop allocation-free code without compromising readability. I am doing it for a long time, and it is awesome!
from accessors.jl.
from accessors.jl.
@chakravala I am curious why you are interested in this package.
from accessors.jl.
from accessors.jl.
from accessors.jl.
You are definitely not understanding the behavior. This LLVM output is not huge, it is minimal! Just remove the comments (those lines started by ;
) and you will see. Just for comparison, here is the output of calling the constructor as you said:
function modstruct3(s::MyStruct)
return MyStruct(10, s.b, s.c, 10)
end
julia> modstruct3(MyStruct(1, 2, 3, 4))
MyStruct(10, 2, 3, 10)
julia> @code_llvm modstruct3(MyStruct(1, 2, 3, 4))
; @ REPL[16]:1 within `modstruct3`
define void @julia_modstruct3_272([4 x i64]* noalias nocapture noundef nonnull sret([4 x i64]) align 8 dereferenceable(32) %0, [4 x i64]* nocapture noundef nonnull readonly align 8 dereferenceable(32) %1) #0 {
top:
; @ REPL[16]:2 within `modstruct3`
; ┌ @ Base.jl:37 within `getproperty`
%memcpy_refined_src = getelementptr inbounds [4 x i64], [4 x i64]* %1, i64 0, i64 1
; └
%newstruct.sroa.0.0..sroa_idx = getelementptr inbounds [4 x i64], [4 x i64]* %0, i64 0, i64 0
store i64 10, i64* %newstruct.sroa.0.0..sroa_idx, align 8
%newstruct.sroa.2.0..sroa_idx5 = getelementptr inbounds [4 x i64], [4 x i64]* %0, i64 0, i64 1
; ┌ @ REPL[2]:2 within `MyStruct`
%2 = bitcast i64* %memcpy_refined_src to <2 x i64>*
%3 = load <2 x i64>, <2 x i64>* %2, align 8
; └
%4 = bitcast i64* %newstruct.sroa.2.0..sroa_idx5 to <2 x i64>*
store <2 x i64> %3, <2 x i64>* %4, align 8
%newstruct.sroa.4.0..sroa_idx7 = getelementptr inbounds [4 x i64], [4 x i64]* %0, i64 0, i64 3
store i64 10, i64* %newstruct.sroa.4.0..sroa_idx7, align 8
ret void
}
See? Now, imagine how much typing and error prone would be changing a value of an immutable structure with 100 parameters compared to @reset s.p = <new value>
. That's why Accessors.jl is awesome! IMHO, it should be in Base.
from accessors.jl.
from accessors.jl.
from accessors.jl.
@chakravala, you can either contribute to enhance projects in a respectful manner or walk away. You're just criticizing without any positive effort to tackle the issue that you're talking about and talking like the maintainer owes you! How rude you are!
from accessors.jl.
from accessors.jl.
So, technically, you are also doing "lazy programming" by writing in Julia! Why don't just write in machine code and avoid "laziness" to the extreme!
from accessors.jl.
We appreciate discussions that stay on topic and don't become too personal. Unfortunately, I don't see this one leading to anything constructive.
Please feel free to open more specific and/or actionable issues!
from accessors.jl.
Related Issues (20)
- "Concat lens": combine multiple lenses side by side HOT 7
- Assemble an object from optics HOT 7
- `hasproperty()` analogue for optics HOT 3
- IndexLens and changing the container size HOT 3
- `Base.show` ambiguity
- @reset naming convention HOT 4
- fate of insert and delete after these functions get into Base
- How to @reset when the field is known only by its equivalent symbol. HOT 2
- Only a single function argument can be the optic target HOT 3
- [Feature request] Set multiple fields at once HOT 6
- Errors in extensions during precompilation HOT 5
- multi-argument modify HOT 4
- `set` for `StructArray`
- To be or not to be HOT 3
- Traversal order of `Recursive` HOT 11
- `==` not defined for `IndexLens` HOT 4
- String properties not supported HOT 3
- Tests fail on 1.11 HOT 2
- `@(re)set` very slow when a parametric inner constructor is defined? HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from accessors.jl.