# Problem with mutation and copying of Matrices/Vectors

I have the below MWE of my code. Here, `R.I_prev = R.I;` is working as copy but I found that it works as mutation in my code, so any change of `R.I` will change directly `R.I_prev`. I faced this issue many times. Can any body guide me if there are some rules that I am missing?

``````Base.@kwdef mutable struct Rs
I::Vector{Float64} = [2,2,2]
I_prev::Vector{Float64} = [1,1,1]
end
R = Rs();
function CC(R)
I_temp = [3;3;3]
R.I_prev = R.I;
R.I = I_temp;
end
CC(R);
julia> R
Rs([3.0, 3.0, 3.0], [2.0, 2.0, 2.0])
``````

This syntax does not copy data from one array into the other. Instead, it replaces `R.I_prev` by `R.I`.

Broadcasting does what you want: `R.I_prev .= R.I`.

Note that, if you only want to move data around, you can actually make your struct immutable. This will still allow modifications to the elements of the `I` and `I_prev` arrays, while preventing precisely the issue that youâ€™re seeing.

4 Likes

Note that if you are really working with lots of little 3-component vectors (e.g. representing positions in 3d), you might consider using StaticArrays. (With `StaticArrays` you can use `=` for copying.)

3 Likes

Thank you!
Actually, I dont really get the difference between `replace, broadcast, mutate, copy`. Can you support examples about them?

Got it and thank you for your help.

@stevengj
I am using a vector of `Rs` to access as `R[index-1].field[index-2]`, as as in below (do you recommend another faster way?)

``````Base.@kwdef mutable struct Rs
I::Vector{Float64} = [2,2,2]
I_prev::Vector{Float64} = [1,1,1]
Dot::Array{Float64, 2} = [0 0 0; 0 0 0; 0 0 0]
end
R = Rs[];
push!(R, Rs()); # the values of fields may change in the code
push!(R, Rs()); # the values of fields may change in the code
#=
do works on R[index-1].field[index-2]
=#
``````

Does using `StaticArrays` also helps here such as in below?

``````Base.@kwdef mutable struct Rs
I::MVector{Float64} = [2,2,2]
I_prev::MVector{Float64} = [1,1,1]
Dot::MArray{Float64, 2} = [0 0 0; 0 0 0; 0 0 0]
end
``````

After this, `R.I` and `R.I_prev` do not point to the same array, so changes to one should not affect the other.

It is possibly overkill to have a mutable struct with mutable fields. Which parts (if any) of your type do you really need to mutate?

Have you considered making the struct entirely immutable with immutable fields? In some cases that can yield performance and safety improvements.

1 Like

@DNF the format of fields (and struct) are not changing but the values inside the fields are changing as in below:

``````Base.@kwdef mutable struct Rs
I::Vector{Float64} = [2,2,2]
I_prev::Vector{Float64} = [1,1,1]
Dot::Array{Float64, 2} = [0 0 0; 0 0 0; 0 0 0]
end
R = Rs[];
push!(R, Rs()); # the values of fields may change in the code
push!(R, Rs()); # the values of fields may change in the code
#=
do works on R[index-1].field[index-2]
=#
``````

Do you think I can delete the `mutable` in front of `struct`?
Maybe I dont really know the meaning of `mutable` in `struct`. For me, it means I can change the values inside the fields, am I right?

Iâ€™m confused, youâ€™re not changing (â€śmutatingâ€ť) any of the values of the fields of a given `Rs` struct here, youâ€™re only adding a new `Rs` struct to the array `R`. That is, youâ€™re not showing any code that would require an `MVector` as opposed to an `SVector`.

1 Like

@stevengj
Here

for example,

``````#=
R[index-1].field1[index-2] = R[index-1].field2[index-2] + R[index-1].field3[index-2]
=#
``````

It looks to me like you may want mutable fields (i.e. `MVector`), but you donâ€™t need `Rs` to be mutable. Just delete `mutable`, and see how it goes

3 Likes

@DNF Mutable structure means its number, names, and values of its fields are changing, correct? So deleting the work `mutable` before structure means so this means its number, names, and values of its fields are not changing, correct?
Since I only need to change he values of the fields then I can only follow the below suggestion, correct?

What is about the `Dot` field, `MMatrix`?

``````Base.@kwdef mutable struct Rs
I::MVector{Float64} = [2,2,2]
I_prev::MVector{Float64} = [1,1,1]
Dot::MMatrix{Float64, 2} = [0 0 0; 0 0 0; 0 0 0]
end
``````

This is not how you declare an `MVector` (or an `SVector`) â€” the distinguishing fact about staticarrays is that the size of the array is part of the type. This makes them fast for small fixed sizes, but also less flexible since you canâ€™t change the size without changing the type. Also, to declare a literal `MVector` you can use `@MVector`:

``````julia> @MVector [2,2,2]
3-element MVector{3, Int64} with indices SOneTo(3):
2
2
2
``````

Note that this also helpfully shows the type. Similarly for `MArray`. I would start with something like:

``````Base.@kwdef struct Rs
I::SVector{3, Float64} = @SVector [2,2,2]
I_prev::SVector{3, Float64} = @SVector [1,1,1]
Dot::SMatrix{3, 3, Float64, 9} = @SMatrix [0 0 0; 0 0 0; 0 0 0]
end
``````

Here, nothing is mutable to start with. You should only make things mutable if you find that there is an operation you need to do that you canâ€™t if it is immutable.

(And you should learn what `mutable struct` means vs mutable fields ala `MVector`, since it seems that you might be confused on this point.)

2 Likes

For example, an immutable version of your `CC` function from above is:

``````CC(R) = Rs(I = @SVector[3,3,3], I_prev = R.I, Dot = R.Dot)
``````

which constructs a new `Rs` struct instead of mutating the old one.

(In general, immutable objects are more efficient in Julia; you should typically work with mutable objects only if you need to reference the same object in two or more places, so that changing the object in one place alters it in the other place. In non performance-sensitive contexts, mutable objects can also sometimes be more convenient, since you donâ€™t have to construct a new object just to change a single field.)

2 Likes

Also, once you get even more Julia experience, you would tend to define this as a parameterized type, e.g.

``````Base.@kwdef struct Rs{T<:Number}
I::SVector{3, T} = @SVector [2,2,2]
I_prev::SVector{3, T} = @SVector [1,1,1]
Dot::SMatrix{3, 3, T, 9} = @SMatrix [0 0 0; 0 0 0; 0 0 0]
end
``````

which defines a whole â€śfamilyâ€ť of types `Rs{T}` for any numeric type `T`. That way, you can use the same code for double precision (`Float64`), single precision (`Float32`), and even more exotic types like unitful values or dual numbers for automatic differentiation.

But I would recommend learning the basics first by hard-coding `Float64`; you can always upgrade your code to parameterized types later, and in the meantime they are trickier to work with.

3 Likes

@stevengj
Thank you very much for your explanations. Starting from this version below

and if I need to do some operations such as:

``````R = Rs[];
push!(R, Rs());
push!(R, Rs());
R[2].I .= R[1].I + R[1].I_prev
``````

Then I need to define the structure from the beginning as below, correct?

``````Base.@kwdef struct Rs
I::MVector{3, Float64} = @MVector [2,2,2]
I_prev::MVector{3, Float64} = @MVector [1,1,1]
Dot::MMatrix{3, 3, Float64, 9} = @MMatrix [0 0 0; 0 0 0; 0 0 0]
end
``````

No. To change the value of `R[2].I`, you need a `mutable struct`, but you donâ€™t need the field to be an `MVector`. If you just do

``````R[2].I = R[1].I + R[1].I_prev
``````

then it will work with `SVector` â€” it is replacing the value of `I`, not overwriting the contents of a mutable object. (You donâ€™t need `.=` with `SVector` because for `SVector` making a copy is essentially zero cost, since itâ€™s not heap-allocated.)

However, you could also accomplish this with a non-mutable `struct` via

``````R[2] = Rs(I = R[1].I + R[1].I_prev, I_prev = R[2].I_prev, Dot = R[2].Dot)
``````

(In many cases this will be more efficient because non-mutable structs are stored in-line in the array, not as pointers to locations elsewhere on the heap.)

2 Likes

For example, numbers are immutable in Julia. If you have `x = 3`, that doesnâ€™t mean you canâ€™t change the value of `x`! But if you do `x = 4` then you are making `x` refer to a new value â€” you arenâ€™t changing the value of `3`! That is:

``````x = 3
y = x
x = 4
y # still 3!
``````

In contrast, a `Vector` is mutable. If you have `x = [3,4,5]`, and you do `x[1] = 7`, then you are changing the contents of the array in-place:

``````x = [3,4,5]
y = x # not a copy â€” y "points" to the same object
x[1] = 7
y # contents are now [7,4,5]
``````

The signature of a mutable object is that if you change it, then other references to the object (via `name = object`) â€śseeâ€ť the change.

If `R.I` is an `SVector` in a mutable object `R`, then if you do:

``````y = R.I
R.I = @SVector [3,4,5]    # only possible if R is a mutable struct
y # hasn't changed!
``````

whereas if `R.I` is a mutable object like a `Vector` or an `MVector`, then even if `R` is a (non-mutable) `struct`, you can change the contents of `R.I`:

``````y = R.I
R.I .= @SVector [3,4,5] # .= changes the *contents* of R.I
R.I[1] = 2  # you can also change individual elements
y # prints [2,4,5] â€” it "sees" the change
``````
2 Likes

What do you mean by â€śnumberâ€ť and â€śnamesâ€ť? You cannot add new fields to an existing `struct` or change the name of its fields, independently if the `struct` is `mutable` or not.

The keyword `mutable` just means you can replace the value/object stored in each field after the `struct` creation. For example, if you create an immutable `struct` with only `Int` values, then you cannot change anything, because you cannot change what the fields refer to (canâ€™t change the `Int` object stored), nor you can change the `Int` objects themselves (`Int`s are immutable). However, if you create an immutable `struct` with an `Vector` inside, then you cannot replace the `Vector` object in the field by another `Vector` object that you have allocated after, but the stored `Vector` itself can be changed because it is mutable (you can call `push!`, `empty!`, or assign new values to specific positions). Both the `mutable` and its absence (the default immutability) are not recursive within the `struct`.

2 Likes