# Best Practices for Mostly Immutable Composite Types

**URL:** <https://discourse.julialang.org/t/best-practices-for-mostly-immutable-composite-types/38501>\
**Category:** New to Julia\
**Created:** [April 30, 2020, 6:58pm UTC](https://discourse.julialang.org/t/best-practices-for-mostly-immutable-composite-types/38501 "2020-04-30T18:58:36Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![forever\_learning](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/forever_learning/32/14880_2.png) [@forever\_learning](https://discourse.julialang.org/u/forever_learning)\
**Post date:** [April 30, 2020, 6:58pm UTC](https://discourse.julialang.org/t/best-practices-for-mostly-immutable-composite-types/38501/1 "2020-04-30T18:58:36Z")

</div>

Hello,

First off, thank you to everyone that contributes to the Julia ecosystem! The more I read the more I become impressed with the size and expertise of the community. As a heavy Matlab user I am excited to move what work I can towards Julia and hopefully get to a place where I can contribute back to the community.

My question here involves the best practices for utilizing composite types in which all but one or two of the fields are immutable.

For example, suppose I am trying to model an airplane for use within a larger swarm simulation. I have had success in implementing something like:

```julia
using StaticArrays

mutable struct SimpleAirplane
    # these fields never change after initialization:
    wing_area::Float64
    mass::Float64
    CL::Float64
    CD::Float64
    #more fields...
    #...
    #...
    # these fields change often:
    X::MVector{3, Float64}
    V::MVector{3, Float64} 
end

function move!(A::SimpleAirplane,dt::Number)
    A.X = A.X + A.V*dt
end

A = SimpleAirplane(1,10,1,0.1,[0,0,-100],[20,0,0])
move!(A,1.0)

```

I have seen suggestions around the forums and within the user’s manual on using immutable types where possible to facilitate performance. While this is not really an issue for me currently I want to adopt best practices wherever I can. As such, I was wondering if there is a better way to approach this kind of problem? I guess my concrete questions would be:

- Is a mutable struct the appropriate container for this use case? What other containers might make sense?
- Is there a way to designate only a subset of fields as mutable?
- How substantial (if at all) is the performance hit for keeping SimpleAirplane mutable?

Thanks!

---

<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:** [April 30, 2020, 7:42pm UTC](https://discourse.julialang.org/t/best-practices-for-mostly-immutable-composite-types/38501/2 "2020-04-30T19:42:49Z")

</div>

You don’t need to keep `SimpleAirplane` mutable at all. You never need to change the vectors `X` and `V`, just their contents. Immutable just refers to the value of the fields. For `MVectors` (or other mutable structures) that value is their address.

---

<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:** [April 30, 2020, 8:56pm UTC](https://discourse.julialang.org/t/best-practices-for-mostly-immutable-composite-types/38501/3 "2020-04-30T20:56:28Z")

</div>

> [@Oscar\_Smith](#):
>
> You don’t need to keep `SimpleAirplane` mutable at all. You never need to change the vectors `X` and `V` , just their contents.

Seconding that.  
As you already have mutable `X` and `V`, just mutate them:

```julia
A.X .+= A.V .* dt

```

The “dotted” syntax does in-place mutation and operation fusion automagically.

In other cases, when one wants a single mutable scalar field, I think, it’s fine to just go with a mutable struct. The key is to define the public interface via functions, and leave data fields an implementation detail.

The performance difference between mutable and immutable structs is hard to quantify for a general case. Immutable `isbits` structs are passed by value, so that big structs may be slow due to excessive copying. Mutables, of course, add an extra indirection, but are cheap to pass around.

Immutables are often thought of as a better alternative exactly because one can’t accidentally re-bind a data field holding a mutable type to another object instead of mutating it. Mutation is usually cheaper than allocating a new object, sometimes much cheaper.

---

<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:** [April 30, 2020, 11:00pm UTC](https://discourse.julialang.org/t/best-practices-for-mostly-immutable-composite-types/38501/4 "2020-04-30T23:00:36Z")

</div>

> [@Vasily\_Pisarev](#):
>
> Immutable `isbits` structs are passed by value, so that big structs may be slow due to excessive copying.

My understanding is that this depends, and that the compiler is free to avoid copying of immutables in many cases.

---

<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:** [May 1, 2020, 5:59pm UTC](https://discourse.julialang.org/t/best-practices-for-mostly-immutable-composite-types/38501/5 "2020-05-01T17:59:41Z")

</div>

It looks like the compiler isn’t always clever enough, especially when it comes to replacing an immutable object with its slightly modified copy.

But what I really wanted to say is that although immutable types are quite useful and must be the first thing to try, one shouldn’t take them as a silver bullet or a dogma or be afraid of being ashamed for using mutable types.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [May 1, 2020, 6:32pm UTC](https://discourse.julialang.org/t/best-practices-for-mostly-immutable-composite-types/38501/6 "2020-05-01T18:32:30Z")

</div>

I would say that if you have only a couple fields in your struct that need to be mutable, I would just wrap them in a `Ref`. By playing around with `getfield` and `getproperty`, you can even make it act just like only one field was mutable:

```julia
struct Foo
    x::Int
    y::Float64
    z::Base.RefValue{Complex{Float64}} # This is the mutable field
    Foo(x, y, z::Complex) = new(x, y, Ref{Complex{Float64}}(z))
end
function Base.getproperty(f::Foo, s::Symbol)
    if s === :z
        getfield(f, :z)[]
    else
        getfield(f, s)
    end
end 
function Base.setproperty!(f::Foo, s::Symbol, x)
    if s === :z
        getfield(f, :z)[] = x
    else
        throw(ErrorException("Only the field z in Foo can be changed"))
    end
end
Base.show(io::IO, f::Foo) = print(io, "Foo($(f.x), $(f.y), $(f.z))")

```

Now at the `REPL`:

```julia
julia> f = Foo(1, 2.0, 3 + 2im)
Foo(1, 2.0, 3.0 + 2.0im)

julia> f.z
3.0 + 2.0im

julia> f.z = 5 + 2im
5 + 2im

julia> f
Foo(1, 2.0, 5.0 + 2.0im)

julia> f.x = 1
ERROR: Only the field z in Foo can be changed

```

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [May 2, 2020, 6:12am UTC](https://discourse.julialang.org/t/best-practices-for-mostly-immutable-composite-types/38501/7 "2020-05-02T06:12:04Z")

</div>

> [@Vasily\_Pisarev](#):
>
> although immutable types are quite useful and must be the first thing to try, one shouldn’t take them as a silver bullet or a dogma or be afraid of being ashamed for using mutable types.

I don’t think that anyone is being shamed for mutable composite types 😉

But they have a cost that is not captured in simple benchmarks: mutable state almost always makes the code more complicated and harder to reason about. This means either much more careful work, or subtle bugs, which are usually tricky to find.

I find that it is usually worth it to pay even a small price in performance to avoid this. The great thing about Julia’s implementation is that this price is usually really tiny.
