# Can I modify the fields of a designed structure?

I was working on a structure with theirs fields are vectors and matrices and I have a vector of it. I need to change elements of this vector to be of a structure which its fields are static vectors and matrices. How can I do that?

I’m not sure what is your doubt, but be careful in that:

``````julia> isconcretetype(MVector{Float64})
false

julia> isconcretetype(MVector{3,Float64})
true

julia> isconcretetype(MMatrix{Float64})
false

julia> isconcretetype(MMatrix{3,3,Float64,9})
true

``````

(meaning that your `RRs` structure has abstract fields as it is)

Concerning the rest, I don’t think I get what you want, but maybe something like this:

``````julia> struct A
x::Vector{Float64}
end

julia> struct B
x::SVector{3,Float64}
end

julia> B(a::A) = B(SVector{3,Float64}(a.x...))
B

julia> a = A(rand(3))
A([0.8719748854921427, 0.48118038068468383, 0.9809479464441135])

julia> B(a)
B([0.8719748854921427, 0.48118038068468383, 0.9809479464441135])

julia> v = [ A(rand(3)), A(rand(3)) ]
2-element Vector{A}:
A([0.3015634495239551, 0.6358999576371009, 0.09630161737144594])
A([0.5218204629518881, 0.289523727629152, 0.16346835337852283])

julia> B.(v)
2-element Vector{B}:
B([0.3015634495239551, 0.6358999576371009, 0.09630161737144594])
B([0.5218204629518881, 0.289523727629152, 0.16346835337852283])

``````
2 Likes

You don’t need the `MVector(....)` call at all when constructing `B`. You can write this as simply as:

``````B(a::A) = B(a.x, a.d)
``````

You can also automatically generate a function like this with `@eval`:

``````@eval B(a::A) = B(\$([:(a.\$x) for x in fieldnames(A)]...))
``````
2 Likes

Thank you very much!
One thing please, are the below structures are identical?

``````struct B1
d::SVector{3,Float64}
end

struct B2
d::MVector{3,Float64}
end

mutable struct B3
d::SVector{3,Float64}
end

mutable struct B4
d::MVector{3,Float64}
end
``````

In which sense? What do you mean by identical?

Sorry if the word was not clear. Actually, I could not recognize the differences between them.
In my code, I have a vector of structure `Bx` and I am modifying its fields, such as `Bx[i].d = rand(3,3)*rand(3)`. Could you please explain to me which structure is better in my case (in terms of performance).

From where `VVector` comes? I am not aware of this data structure. About the differences:

1. You can only do something like `Bx[i].d = rand(3,3)*rand(3)`, i.e., replacing the whole array in a swoop, if the `struct` you define is mutable.
2. If your `struct` is not mutable, then you can yet change the values inside the matrix if the matrix type is mutable. `MVector` is mutable and, while you cannot replace the whole `MVector` with a new one, you can replace the values inside it with `Bx[i].d .= rand(3,3)*rand(3)` (notice the dot before the equal sign).
3. If your struct is not mutable neither the type of the matrix inside it then you cannot modify its value after creation and must create a new object to pass around each time you need the value to be changed.
1 Like

I am sorry, it is a typo. I have corrected it to be `SVector`

Thank you very much for your explanation!
1- What does `replacing the whole array in a swoop` mean?
2- Can I do `Bx[i].d = rand(3,3)*rand(3)` on the below two structure since they are `mutable`?

About (1), I mean that you cannot replace the array inside the struct by an entirely new array, the array used in the construction of the struct will always be the same, the only thing that can be changed is its contents.

``````julia> struct A; a :: Vector{Int}; end

julia> x = [1, 2, 3]
3-element Array{Int64,1}:
1
2
3

julia> a_var = A(x)
A([1, 2, 3])

julia> a_var.a = [4, 5, 6]
ERROR: setfield! immutable struct of type A cannot be changed
Stacktrace:
 setproperty!(::A, ::Symbol, ::Array{Int64,1}) at ./Base.jl:34
 top-level scope at REPL:1

julia> x
3-element Array{Int64,1}:
1
2
3

julia> a_var.a .= [4, 5, 6]
3-element Array{Int64,1}:
4
5
6

julia> x
3-element Array{Int64,1}:
4
5
6

julia> mutable struct B; b :: Vector{Int}; end

julia> y = [1, 2, 3]
3-element Array{Int64,1}:
1
2
3

julia> b_var = B(y)
B([1, 2, 3])

julia> b_var.b = [4, 5, 6]
3-element Array{Int64,1}:
4
5
6

julia> y
3-element Array{Int64,1}:
1
2
3

julia> b_var.b
3-element Array{Int64,1}:
4
5
6

julia> b_var.b
3-element Array{Int64,1}:
4
5
6

``````
1. Yes, you can.

I fell like the answers to some of your questions could be obtained by just running your code through the REPL.

1 Like

Yes, I tried to run the code in the REPL but I didnt understand the exact difference such as in the below code.
1- The field `d` is static in `B3`, why is it still possible to change it by an entirely new array?
2- Could you please give me an example to show the unique usage for `B3` and `B4` (in terms of replacing/filling the field `d`)?
3- How can I solve the below error?

``````julia> mutable struct B4
d::MVector{3,Float64}
end
julia> mutable struct B3
d::SVector{3,Float64}
end

julia> a_var = B3([1,2,3])
B3([1.0, 2.0, 3.0])

julia> a_var.d = [4,5,6]
3-element Vector{Int64}:
4
5
julia> a_var.d[1:2] = [4,5]
ERROR: setindex!(::SVector{3, Float64}, value, ::Int) is not defined.
Stacktrace:
julia> a_var.d[1:2] .= [4,5]
ERROR: setindex!(::SVector{3, Float64}, value, ::Int) is not defined.
Stacktrace:
``````
1. Yes. You cannot replace values inside `d` because the `SArray` object is immutable. However, the `B3` object is mutable, and therefore a new object may be assigned to field `d`.
2. What do you mean by unique usage? I do not undertsand the question.
3. You cannot “solve” the error. It is a consequence of you using a `SArray` (i.e., an immutable object), you cannot mutate an `SArray`. The best you can do is to create a new array with the changed values and assign it. `a_var.d = [4, 5, a_var.d]`
1 Like

What is the difference between `mutate`, ` =` assignment `.=` assignment in julia?

`mutate` does not exist, not as a function, at least. Mutation happens when you use `=` but the left-hand side is not just a variable name but a field inside an object (or a position inside an array). For example, `a = 10` is a binding that binds the name `a` to the value 10 (i.e., not mutation) but `a.my_field = 10` is an assignment of the value 10 to the field `my_field` of object `a` (i.e., a mutation). `a = 10` is a language primitive, `a.my_field = 10` calls `Base.setproperty!(a, :my_field, 10)` and its meaning can be changed by adding methods to this function. Finally, `.=` is another completely distinct thing, it can never be used for binding (i.e., to create a new variable) it only works on already existing objects/variables that are containers and it mutates each element of the container in the left-hand side to the value of the elements on the container of the right-hand side. You can use `?.=` in the REPL to check its documentation, it is replaced by Julia to a call to `broadcast!(identity, left_hand_variable, right_hand_variable)`.

In other words, things that look similar are completely different things, in fact.

2 Likes

It compiles other previous answers to that.

1 Like

Thank you very much for explanation. I know that in Julia a scalar is immutable. However, if I have an immutable structure `B3`, is there any way (a trick) to change its scalar property `s` to be mutable, i.e. `B3` remains immutable?

``````struct B3
d::MVector{3,Float64}
s::Int64
end
a_var = B3([1,2,3],0)
a_var.d[1:3] = [6,6,6]
a_var.s = Int(4)
ERROR: setfield!: immutable struct of type B3 cannot be changed
``````

Not really.

You can change field `s` to be of type `Base.RefValue{Int64}` but this needs the `struct` definition to be different and you will need to use `[]` every time you want to access the value, as in:

``````julia> struct B3
s::Base.RefValue{Int64}
end

julia> b3 = B3(Ref(1))
B3(Base.RefValue{Int64}(1))

julia> b3.s[]
1

julia> b3.s[] = 2
2

julia> b3
B3(Base.RefValue{Int64}(2))
``````

What you will probably want is to rebuild the object with everything the same except the changed value.

``````julia> struct B3
d::Vector{Float64}
s::Int64
end

julia> b3 = B3([1, 2, 3], 10)
B3([1.0, 2.0, 3.0], 10)

julia> b3 = B3(b3.d, 11)
B3([1.0, 2.0, 3.0], 11)
``````

There is a library called `Setfield.jl` that make it easier to re-create an object changing just a single field, but note this is not the same as changing the original.

1 Like

Thank you very much for your very help feedbacks!