GithubHelp home page GithubHelp logo

Comments (14)

aplavin avatar aplavin commented on May 28, 2024 1

It's built on ConstructionBase.setproperties that provides an efficient way to set multiple properties. Feel free to use that function!

from accessors.jl.

ronisbr avatar ronisbr commented on May 28, 2024 1

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.

ronisbr avatar ronisbr commented on May 28, 2024 1

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.

chakravala avatar chakravala commented on May 28, 2024

from accessors.jl.

jw3126 avatar jw3126 commented on May 28, 2024

@chakravala I am curious why you are interested in this package.

from accessors.jl.

chakravala avatar chakravala commented on May 28, 2024

from accessors.jl.

chakravala avatar chakravala commented on May 28, 2024

from accessors.jl.

ronisbr avatar ronisbr commented on May 28, 2024

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.

chakravala avatar chakravala commented on May 28, 2024

from accessors.jl.

chakravala avatar chakravala commented on May 28, 2024

from accessors.jl.

shayandavoodii avatar shayandavoodii commented on May 28, 2024

@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.

chakravala avatar chakravala commented on May 28, 2024

from accessors.jl.

ronisbr avatar ronisbr commented on May 28, 2024

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.

aplavin avatar aplavin commented on May 28, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.