# Copyto! issue when updating fields of struct

**URL:** <https://discourse.julialang.org/t/copyto-issue-when-updating-fields-of-struct/85052>\
**Category:** General Usage\
**Tags:** question, performance, mutable-structure, staticarrays\
**Created:** [July 31, 2022, 7:35am UTC](https://discourse.julialang.org/t/copyto-issue-when-updating-fields-of-struct/85052 "2022-07-31T07:35:25Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![WDM-Computation](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wdm-computation/32/34681_2.png) [@WDM-Computation](https://discourse.julialang.org/u/WDM-Computation)\
**Post date:** [July 31, 2022, 7:35am UTC](https://discourse.julialang.org/t/copyto-issue-when-updating-fields-of-struct/85052/1 "2022-07-31T07:35:25Z")

</div>

Hello! This is somewhat of a followup question from before. I have some structs using StaticArrays for performance reasons, which has been working great until now. It seems that as long as I am broadcasting ( ‘.=’ ) an array to the field, everything seems fine. But when I want to change the value of ‘s’ (a Float64), I run into an error, which I’ve listed below the example code.

```julia
using StaticArrays

struct Particle
    pos::MVector{3,Float64}
    s::Float64
end

P = Particle(MVector(0., 0., 0.), 1.)
P.pos .= [1.,1.,1.] # runs (even with Array not S.A.)
P.s .= 2. # copyto! syntax error

```

```julia
julia> include("structTest.jl")
ERROR: LoadError: MethodError: no method matching copyto!(::Float64, ::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{0}, Tuple{}, typeof(identity), Tuple{Float64}})
Closest candidates are:
  copyto!(::Any, ::Base.Broadcast.Broadcasted{<:StaticArrays.StaticArrayStyle}) at ~/.julia/packages/StaticArrays/G7IlJ/src/broadcast.jl:68
  copyto!(::AbstractArray, ::Base.Broadcast.Broadcasted{<:Base.Broadcast.AbstractArrayStyle{0}}) at /Applications/Julia-1.7.app/Contents/Resources/julia/share/julia/base/broadcast.jl:916
  copyto!(::AbstractArray, ::Base.Broadcast.Broadcasted) at /Applications/Julia-1.7.app/Contents/Resources/julia/share/julia/base/broadcast.jl:913
  ...
Stacktrace:
 [1] materialize!
   @ ./broadcast.jl:871 [inlined]
 [2] materialize!(dest::Float64, bc::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{0}, Nothing, typeof(identity), Tuple{Float64}})
   @ Base.Broadcast ./broadcast.jl:868
 [3] top-level scope
   @ ~/filepath/structTest.jl:10
 [4] include(fname::String)
   @ Base.MainInclude ./client.jl:451
 [5] top-level scope
   @ none:1
in expression starting at 
/filepath/structTest.jl:10

```

Is anyone able to provide some insight into this behavior? I would like to not only fix this issue but to understand why.  
Thank you!

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [July 31, 2022, 8:10am UTC](https://discourse.julialang.org/t/copyto-issue-when-updating-fields-of-struct/85052/2 "2022-07-31T08:10:08Z")

</div>

Your struct is not mutable, hence you can’t reassign the `s` field. Broadcasting is only for _collections/containers_, which a `Float64` is not.

You can broadcast into the `MVector` field because it’s a mutable object.

---

<div class="post-metadata">

**Author:** ![WDM-Computation](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wdm-computation/32/34681_2.png) [@WDM-Computation](https://discourse.julialang.org/u/WDM-Computation)\
**Post date:** [July 31, 2022, 5:01pm UTC](https://discourse.julialang.org/t/copyto-issue-when-updating-fields-of-struct/85052/3 "2022-07-31T17:01:33Z")

</div>

What would you suggest as the most performant way to proceed? I am thinking of either redefining the struct as mutable, or storing each field in a static array. The first should be easier to implement, but I am worried about performance “gotchas”.

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [July 31, 2022, 5:45pm UTC](https://discourse.julialang.org/t/copyto-issue-when-updating-fields-of-struct/85052/4 "2022-07-31T17:45:35Z")

</div>

A mutable struct with a `SVector` field is a fine choice.

---

<div class="post-metadata">

**Author:** ![WDM-Computation](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wdm-computation/32/34681_2.png) [@WDM-Computation](https://discourse.julialang.org/u/WDM-Computation)\
**Post date:** [July 31, 2022, 6:12pm UTC](https://discourse.julialang.org/t/copyto-issue-when-updating-fields-of-struct/85052/5 "2022-07-31T18:12:12Z")

</div>

I just played around two different solutions, shown below with benchmarks for future reference.

```julia
module S

N=30_000_000

using StaticArrays, Random

mutable struct MParticle
    pos::SVector{3,Float64}
    s::Float64
end

struct SParticle
    pos::MVector{3,Float64}
    s::MVector{1,Float64}
end

PM = MParticle(SVector(0., 0., 0.), 1.)
PS = SParticle(MVector(0., 0., 0.), MVector(1.))

# Benchmark
@time for i in 1:N
    PM.pos = SVector(rand(),rand(),rand())
    PM.s = rand()
end

@time for i in 1:N
    PS.pos .= MVector(rand(),rand(),rand())
    PS.s .= MVector(rand())
end

# module end
end

```

```julia
julia> include("structTest.jl")
  4.830332 seconds (270.00 M allocations: 5.812 GiB, 11.33% gc time, 0.17% compilation time)
  4.781887 seconds (270.00 M allocations: 5.812 GiB, 11.59% gc time, 0.04% compilation time)
Main.S

```

I am surprised that both methods seem equally performant for sufficiently large N, although I noticed SParticle had consistently lower % compilation time.

The first structure definition seems cleaner, so I think I will moved forward in implementing the mutable struct with immutable fields.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [July 31, 2022, 6:14pm UTC](https://discourse.julialang.org/t/copyto-issue-when-updating-fields-of-struct/85052/6 "2022-07-31T18:14:24Z")

</div>

> [@WDM-Computation](#):
>
> ```julia
> # Benchmark
> @time for i in 1:N
> PM.pos = SVector(rand(),rand(),rand())
> PM.s = rand()
> end
> 
> ```

Don’t benchmark in global scope. Put the thing you want to benchmark in a function and `@benchmark` that function (from BenchmarkTools.jl). Don’t use global variables during benchmarking (or for otherwise performance critical objects).

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [July 31, 2022, 6:22pm UTC](https://discourse.julialang.org/t/copyto-issue-when-updating-fields-of-struct/85052/7 "2022-07-31T18:22:28Z")

</div>

`MParticle`’s advantage is that it will require 1 allocation to construct, and is 1 contiguous block of memory, while `SParticle` requires 2 allocations to construct, and has 2 separate addresses.

Neither of these differences will be tested in a micro benchmark updating the same object in place.

---

<div class="post-metadata">

**Author:** ![WDM-Computation](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wdm-computation/32/34681_2.png) [@WDM-Computation](https://discourse.julialang.org/u/WDM-Computation)\
**Post date:** [July 31, 2022, 6:24pm UTC](https://discourse.julialang.org/t/copyto-issue-when-updating-fields-of-struct/85052/8 "2022-07-31T18:24:48Z")

</div>

```julia
function update1(PM, N)
    @time for i in 1:N
        PM.pos = SVector(rand(),rand(),rand())
        PM.s = rand()
    end
end

function update2(PS, N)
    @time for i in 1:N
        PS.pos .= MVector(rand(),rand(),rand())
        PS.s .= MVector(rand())
    end
end

update1(PM, N)
update2(PS, N)

```

```julia
julia> include("structTest.jl")
WARNING: replacing module S.
  0.916128 seconds
  0.904219 seconds
Main.S

```

Excellent point. Thank you!

---

<div class="post-metadata">

**Author:** ![WDM-Computation](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wdm-computation/32/34681_2.png) [@WDM-Computation](https://discourse.julialang.org/u/WDM-Computation)\
**Post date:** [July 31, 2022, 6:26pm UTC](https://discourse.julialang.org/t/copyto-issue-when-updating-fields-of-struct/85052/9 "2022-07-31T18:26:25Z")

</div>

Do you have further reading on this that you can recommend? I am interested for the sake of curiosity, and this behavior is also important to the performance of my simulation at large.
