# Structs: mutable versus immutable

**URL:** <https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889>\
**Category:** New to Julia\
**Tags:** question, struct\
**Created:** [January 25, 2021, 7:02am UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889 "2021-01-25T07:02:57Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![owinter92](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/owinter92/32/21346_2.png) [@owinter92](https://discourse.julialang.org/u/owinter92)\
**Post date:** [January 25, 2021, 7:02am UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/1 "2021-01-25T07:02:57Z")

</div>

Hi, I struggle to understand the behavior of the following code:

```julia
struct TestStruct
    a::Int64
    b::Array{Float64,1}
end
function test_function!(s)
    s=TestStruct(2,s.b)
end
a=TestStruct(1,rand(1_000))
test_function!(a)
a

```

Why is `a` not updated to `a.a=2`?

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [January 25, 2021, 7:13am UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/2 "2021-01-25T07:13:24Z")

</div>

`struct`s in Julia are not `mutable` (for that, you want a `mutable struct`. Also, Julia uses Pass By Sharing, so `test_function` takes an `s`, creates a new `s` and returns it. Assuming `TestStruct` was `mutable`, you would want. `s.a = 2` which changes the value of `s.a` instead of creating a new object for `s`

---

<div class="post-metadata">

**Author:** ![owinter92](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/owinter92/32/21346_2.png) [@owinter92](https://discourse.julialang.org/u/owinter92)\
**Post date:** [January 25, 2021, 7:25am UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/3 "2021-01-25T07:25:20Z")

</div>

Yes, I know. Unfortunately, the mutable struct is very slow. Let me reformulate my question: Can I mutate only array in Julia via function? The problem really is that mutable struct is slow and if I want to mutate some pack of data and do not want to use return because it is additional cost.

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [January 25, 2021, 7:37am UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/4 "2021-01-25T07:37:12Z")

</div>

Can you give an example that shows what you want in context?

To “modify” a field in a struct, you can write

```julia
a = modify_field(a)

```

If there’s an array of `a`s, then you can use

```julia
map!(modify_field, array, array)

```

to modify the array in-place, assuming the transformation to be done depends only on one individual value.

---

<div class="post-metadata">

**Author:** ![owinter92](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/owinter92/32/21346_2.png) [@owinter92](https://discourse.julialang.org/u/owinter92)\
**Post date:** [January 25, 2021, 7:45am UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/5 "2021-01-25T07:45:27Z")

</div>

Thanks, I will check it out.

---

<div class="post-metadata">

**Author:** ![owinter92](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/owinter92/32/21346_2.png) [@owinter92](https://discourse.julialang.org/u/owinter92)\
**Post date:** [January 25, 2021, 8:01am UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/6 "2021-01-25T08:01:24Z")

</div>

I just remembered that there is also [jw3126](https://github.com/jw3126) / **[Setfield.jl](https://github.com/jw3126/Setfield.jl)** package.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [January 25, 2021, 8:27am UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/7 "2021-01-25T08:27:47Z")

</div>

Setfield is nice, but no faster than doing it manually, it’s just more convenient notation.

> [@owinter92](#):
>
> Unfortunately, the mutable struct is very slow.

Mutable structs should not be ‘very slow’, maybe not quite as fast as an immutable struct, but if it’s ‘very slow’, I suspect something else is wrong.

Anyway, if you are mutating the array inside the struct, that is only possible because the array _itself_ is mutable.

---

<div class="post-metadata">

**Author:** ![owinter92](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/owinter92/32/21346_2.png) [@owinter92](https://discourse.julialang.org/u/owinter92)\
**Post date:** [January 25, 2021, 8:53am UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/8 "2021-01-25T08:53:30Z")

</div>

> Anyway, if you are mutating the array inside the struct, that is only possible because the array _itself_ is mutable.

Yes, that is clear.

Regarding the speed:

```julia
mutable struct MutableS
    a::Int
    b::Array{Float64,1}
end
struct S
    a::Int
    b::Array{Float64,1}
end

function test_ms(val)
    for i in 1:1_000_000
        val.a = i
    end
end

function test_s(val)
    for i in 1:1_000_000
        @set val.a = i
    end
end

ms=MutableS(1,rand(1_000));
s=S(1,rand(1_000));

@benchmark test_ms(ms)
BenchmarkTools.Trial: 
  memory estimate: 0 bytes
  allocs estimate: 0
  --------------
  minimum time: 313.262 μs (0.00% GC)
  median time: 344.536 μs (0.00% GC)
  mean time: 409.776 μs (0.00% GC)
  maximum time: 826.716 μs (0.00% GC)
  --------------
  samples: 10000
  evals/sample: 1

@benchmark test_s(s)
BenchmarkTools.Trial: 
  memory estimate: 0 bytes
  allocs estimate: 0
  --------------
  minimum time: 17.570 ns (0.00% GC)
  median time: 19.179 ns (0.00% GC)
  mean time: 23.652 ns (0.00% GC)
  maximum time: 485.720 ns (0.00% GC)
  --------------
  samples: 10000
  evals/sample: 998

```

It is quite a difference. Not sure if I am doing something wrong with mutable structs but it seems to be pretty clear how to use them.

---

<div class="post-metadata">

**Author:** ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)\
**Post date:** [January 25, 2021, 10:13am UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/9 "2021-01-25T10:13:30Z")

</div>

This is a benchmarking problem. The mutable struct gives you a million updates in 400 μs. That’s 0.4 ns per update, corresponding to 1 update per clock cycle on a 2.5 GHz processor. Those who know more details about CPU architecture can say whether this is good or bad but at least it’s in the right ballpark and can hardly count as slow.

The 24 ns for a million supposed updates of an immutable struct is, on the other hand, completely unreasonable. Nothing happens that fast on a CPU. With all certainty the compiler has been smart enough to see that the code doesn’t actually produce anything and has optimized away nearly everything.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [January 25, 2021, 10:27am UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/10 "2021-01-25T10:27:06Z")

</div>

> [@GunnarFarneback](#):
>
> With all certainty the compiler has been smart enough to see that the code doesn’t actually produce anything and has optimized away nearly everything.

And yet that is one reason to prefer immutable structs 🙂

---

<div class="post-metadata">

**Author:** ![tamasgal](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamasgal/32/27946_2.png) [@tamasgal](https://discourse.julialang.org/u/tamasgal)\
**Post date:** [January 25, 2021, 11:14am UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/11 "2021-01-25T11:14:47Z")

</div>

Well, in this made-up example, yes… but we should put that in the actual context to see if immutable structs are the answer to the original problem.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [January 25, 2021, 11:18am UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/12 "2021-01-25T11:18:12Z")

</div>

That benchmark is highly artificial and gives a false impression. It also shows why you should not write loops like that (artificial loops added for timing purposes) into benchmarks. BenchmarkTools already does that for you.

~~In fact, this function does zero work, because it doesn’t even return the new value, so it can just be removed completely:~~ Sorry, this was wrong. It does actually return the last value in the for loop.

> [@owinter92](#):
>
> ```julia
> function test_s(val)
> for i in 1:1_000_000
> @set val.a = i
> end
> end
> 
> ```

---

<div class="post-metadata">

**Author:** ![owinter92](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/owinter92/32/21346_2.png) [@owinter92](https://discourse.julialang.org/u/owinter92)\
**Post date:** [January 25, 2021, 11:38am UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/13 "2021-01-25T11:38:57Z")

</div>

The actual context is finite element grid. I am working on computational fluid dynamics project with fluid-structure interaction capability, i.e., moving grid, i.e., mutating data in `struct`. I was trying to find the right way to store data.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [January 25, 2021, 12:10pm UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/14 "2021-01-25T12:10:47Z")

</div>

I tried to do a better benchmark here. Not sure if it is completely correct, but the results seem reasonable.

I changed some of the names, for various reasons.

```julia
mutable struct MutableS
    a::Int
    b::Array{Float64,1}
end

struct SS
    a::Int
    b::Array{Float64,1}
end

test_ms!(s, val) = (s.a = val)
test_s(s, val) = (@set s.a = val; return s)

ms = MutableS(1, rand(1_000));
s = SS(1, rand(1_000));

```

Benchmark:

```julia
julia> @benchmark test_ms!($(Ref(ms))[], val) setup=(val=rand(0:9))
BenchmarkTools.Trial: 
  memory estimate: 0 bytes
  allocs estimate: 0
  --------------
  minimum time: 1.199 ns (0.00% GC)
  median time: 1.400 ns (0.00% GC)
  mean time: 1.386 ns (0.00% GC)
  maximum time: 26.001 ns (0.00% GC)
  --------------
  samples: 10000
  evals/sample: 1000

julia> @benchmark test_s($(Ref(s))[], val) setup=(val=rand(0:9))
BenchmarkTools.Trial: 
  memory estimate: 0 bytes
  allocs estimate: 0
  --------------
  minimum time: 1.199 ns (0.00% GC)
  median time: 1.300 ns (0.00% GC)
  mean time: 1.335 ns (0.00% GC)
  maximum time: 43.401 ns (0.00% GC)
  --------------
  samples: 10000
  evals/sample: 1000

```

It’s a bit difficult to benchmark so small function.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [January 25, 2021, 12:18pm UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/15 "2021-01-25T12:18:20Z")

</div>

> [@DNF](#):
>
> Sorry, this was wrong. It does actually return the last value in the for loop.

Can I say that I really dislike this implicit return behaviour? I wish explicit `return` statements were required, at least for “long-form functions”.

---

<div class="post-metadata">

**Author:** ![owinter92](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/owinter92/32/21346_2.png) [@owinter92](https://discourse.julialang.org/u/owinter92)\
**Post date:** [January 25, 2021, 12:31pm UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/16 "2021-01-25T12:31:54Z")

</div>

Thanks, I will check [BenchmarkTools.jl](https://github.com/JuliaCI/BenchmarkTools.jl/blob/master/doc/manual.md). I probably overthinking the problem anyway. I will stick with `mutable struct` for larger collections of data and `struct` for smaller, e.g. `Point`.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [January 25, 2021, 12:32pm UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/17 "2021-01-25T12:32:49Z")

</div>

> [@tamasgal](#):
>
> Well, in this made-up example, yes… but we should put that in the actual context to see if immutable structs are the answer to the original problem.

Sure, sorry, I just wanted to point out that the compiler will in general be able to do more optimizations with immutable types.

Concerning the original post:

> [@owinter92](#):
>
> ```julia
> function test_function!(s)
> s=TestStruct(2,s.b)
> end
> a=TestStruct(1,rand(1_000))
> test_function!(a)
> a
> 
> ```

A natural way to obtain what you originally wanted here is simply to return a copy of the value instead of trying to modify it:

```julia
julia> function test_function(s)
          s2 = TestStruct(2,s.b)
          return s2
       end
test_function (generic function with 1 method)

julia> a = TestStruct(1,rand(1_000));

julia> a = test_function(a)
TestStruct(2, ... 

```

You might think: But then I am just copying the struct! Indeed you are, but this is fast and allocation free (edit: actually not true if the field itself is mutable, which is the case here), because immutable structs are generally stored in the fast stack memory. This is no different from doing

```julia
x = 1
x = 2*x

```

except that your struct has more fields than `x`.

I understand that `@set` does no miracle here, it just conveniently does that copy without one having to define the structure explicitly. And there is no gain in performance:

```julia
julia> function change_vec1!(vec)
         for s in vec
           s = TestStruct(2*s.a,s.b)
         end
       end
change_vec1! (generic function with 1 method)

julia> function change_vec2!(vec)
         for s in vec
           @set s.a = 2*s.a
         end
       end
change_vec2! (generic function with 1 method)

julia> vec = [TestStruct(rand(1:10),rand(1_000)) for i in 1:10_000];

julia> @btime change_vec1!(vec)
  5.036 μs (0 allocations: 0 bytes)

julia> vec = [TestStruct(rand(1:10),rand(1_000)) for i in 1:10_000];

julia> @btime change_vec2!(vec)
  5.081 μs (0 allocations: 0 bytes)

```

edit: these benchmarks are wrong as pointed below. (it is true that `@set` is the same as copying the struct, but in these cases the vector of structs is not being modified).

---

<div class="post-metadata">

**Author:** ![owinter92](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/owinter92/32/21346_2.png) [@owinter92](https://discourse.julialang.org/u/owinter92)\
**Post date:** [January 25, 2021, 12:38pm UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/18 "2021-01-25T12:38:47Z")

</div>

> A natural way to obtain what you originally wanted here is simply to return a copy of the value instead of trying to modify it:

That was my idea also but there is additional cost for returning the value out of the function.

Also it seems that you have actually write

```julia
s = @set s.a=1

```

to update value inside of `s`.

Anyway, as I wrote above I was probably overthinking the problem.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [January 25, 2021, 12:54pm UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/19 "2021-01-25T12:54:43Z")

</div>

> [@owinter92](#):
>
> to update value inside of `s` .

Note that this does not update the value of `s`, it _in principle_ copies the entire `s` (which is immutable). Still, that is still faster, than mutating the value `a` of an equivalent mutable struct (and this is because the way mutable and immutable structs are stored in memory):

```julia
julia> mutable struct MutableTestStruct
           a::Int64
           b::Array{Float64,1}
       end

julia> function change_vec3!(vec)
         for s in vec
           s.a = 2*s.a
         end
       end
change_vec3! (generic function with 1 method)

julia> vec = [MutableTestStruct(rand(1:10),rand(1_000)) for i in 1:10_000];

julia> @btime change_vec3!($vec)
  8.692 μs (0 allocations: 0 bytes)

```

~~I said above _in principle_ copies, because if you benchmark those toy examples, you will see that the time is independent of the size of the `b` field, thus clearly that field is not being copied (using `@set` or copying the struct explicitly). The compiler will figure out what is the best way to deal with such an array, probably.~~

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [January 25, 2021, 1:14pm UTC](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889/20 "2021-01-25T13:14:24Z")

</div>

> [@owinter92](#):
>
> That was my idea also but there is additional cost for returning the value out of the function.

Are you sure about this, that it’s not just another benchmarking artefact? Or what are you referring to?

[Next page](https://discourse.julialang.org/t/structs-mutable-versus-immutable/53889.md?page=2)
