# How to design with immutable and also mutable type?

**URL:** <https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465>\
**Category:** General Usage\
**Created:** [February 11, 2020, 12:25pm UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465 "2020-02-11T12:25:17Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)\
**Post date:** [February 11, 2020, 12:25pm UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/1 "2020-02-11T12:25:17Z")

</div>

suppose I have a parametric type as follows:

```julia
struct A{T <: AbstractVector{Float32} }
    data::T
end

setdata!(a::A, x) = (a.data .= x)

```

here `T` could be `Vector{Float32}` or a view etc.

however, I would like to use `SVector` (in `StaticArrays`) also. But as **I need to mutate the contents of `data` over time** , I need to define another struct which is mutable like:

```julia
mutable struct B{T <: AbstractVector{Float32} }
    data::T
end

setdata!(b::B, x) = (b.data = x)

```

so, my question is: is there a more beautiful way to do this? maintaining a immutable type along with another mutable type seems ugly… and the behaviors of `A` and `B` are basically identical, except for `setdata!()`.

another question is: if I just use (the mutable) `B` for all cases, would it be stupid because of the performance penalty caused by mutable types?

thanks.

---

<div class="post-metadata">

**Author:** ![Zach\_Christensen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zach_christensen/32/7220_2.png) [@Zach\_Christensen](https://discourse.julialang.org/u/Zach_Christensen)\
**Post date:** [February 11, 2020, 1:14pm UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/2 "2020-02-11T13:14:06Z")

</div>

Look at ArrayInterface.jl on detecting mutability. I’ll write an example once I’m not on a phone.

---

<div class="post-metadata">

**Author:** ![pixel27](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pixel27/32/8902_2.png) [@pixel27](https://discourse.julialang.org/u/pixel27)\
**Post date:** [February 11, 2020, 2:09pm UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/3 "2020-02-11T14:09:46Z")

</div>

Can I ask why you don’t want to make A mutable? I mean I guess if data is a Vector{Float32}, at a low level you will have 3(?) pointers to get at the data instead of 2. Not sure what the CPU overhead on that would be, but it should be minuscule.

That said, you might be able to do something like:

```julia
struct A{T}
    data::T
end

mutable struct B{T}
    data::T
end

A(d::T) where T <: SVector = A(B(d))

getdata(a::A{T}) where T = a.data
getdata(a::A{T}) where T <: B = a.data.data

```

Granted any changes you want to make to the data will need to use the getdata function.

---

<div class="post-metadata">

**Author:** ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)\
**Post date:** [February 11, 2020, 3:26pm UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/4 "2020-02-11T15:26:32Z")

</div>

thanks. looking forward to your examples.

---

<div class="post-metadata">

**Author:** ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)\
**Post date:** [February 11, 2020, 3:28pm UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/5 "2020-02-11T15:28:38Z")

</div>

> [@pixel27](#):
>
> Can I ask why you don’t want to make A mutable?

I **assume** that a mutable struct is **much** slower than a immutable one, but I’m not sure.

`A(B(d))` not work. `A` and `B` have many (identical) fields other than `data` (not shown for simplicity).

---

<div class="post-metadata">

**Author:** ![Zach\_Christensen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zach_christensen/32/7220_2.png) [@Zach\_Christensen](https://discourse.julialang.org/u/Zach_Christensen)\
**Post date:** [February 11, 2020, 5:37pm UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/6 "2020-02-11T17:37:28Z")

</div>

Wait, do you have some instances where you don’t need to update `data` and that’s why you have two types in the OP? Or will you for sure need to change the `data` for every instance of `A`?

If you will always need to change values within `data` then you don’t want `SVector`. You may want to use `MVector` or just a `Vector` if you’re going to change sizes.

---

<div class="post-metadata">

**Author:** ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)\
**Post date:** [February 12, 2020, 1:09am UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/7 "2020-02-12T01:09:30Z")

</div>

> [@Zach\_Christensen](#):
>
> will you for sure need to change the `data` for every instance of `A` ?

yes sure, I need to change `data` for every instance.

> [@Zach\_Christensen](#):
>
> You may want to use `MVector`

I don’t want to use `MVector` because:

1. it’s much slower than `SVector`
2. everytime I’m **changing all contents** of `data`, not at a particular index. Effectively I will put a **new** `SVector` into `data`

---

<div class="post-metadata">

**Author:** ![Zach\_Christensen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zach_christensen/32/7220_2.png) [@Zach\_Christensen](https://discourse.julialang.org/u/Zach_Christensen)\
**Post date:** [February 12, 2020, 2:44am UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/8 "2020-02-12T02:44:18Z")

</div>

I think I get it. So you want to be able to swap out the `SVector` but you also want the type to not be mutable because all the other fields stay the same and don’t change.

I think what you want to do is something more like:

```julia
struct TypeWithManyFields end

struct SVectorAndFields
    fields::TypeWithManyFields
    data::SVector
end

```

Then make a new instance of `SVectorAndFields` like so:

```julia
old_data = SVectorAndFields(TypeWithManyFields(), SVector(1))

new_data = SVectorAndFields(new_data.fields, SVector(2))

```

---

<div class="post-metadata">

**Author:** ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)\
**Post date:** [February 12, 2020, 3:25am UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/9 "2020-02-12T03:25:02Z")

</div>

> [@Zach\_Christensen](#):
>
> because all the other fields stay the same and don’t change.

no… it’s not the point…

let me try to clarify:

1. I want to have a custom type containing a `data` field which can be a mutable vector (e.g. `Vector`) or an immutable vector (e.g. `SVector`).
2. the **whole** content of `data` has to be updated over time. For mutable vector, it could be done by `obj.data .= v`, i.e. the **contents** of `data` are overwritten by those in `v`. However, for immutable vector, because its content could not be modified, the **field** `data` has to be replaced like `obj.data = v`.
3. now, for `obj.data .= v` we can use a normal (immutable) `struct`. But to accommodate `obj.data = v`, we need a mutable `struct` instead.

the problem is how to get the best from both worlds (i.e. using a fast, immutable `struct` for mutable vector & using a mutable `struct` for immutable vector) **without defining two custom types**.

or, maybe two types are indeed needed, then the question becomes **how to abstract / factor these two types into a single type** as their behaviors are basically identical.

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [February 12, 2020, 3:59am UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/10 "2020-02-12T03:59:52Z")

</div>

FYI, [GitHub - JuliaFolds/BangBang.jl: Immutables as mutables, mutables as immutables.](https://github.com/tkf/BangBang.jl) is aiming at providing a unified API for immutable and mutable objects. In particular, something like `BangBang.@set!! x.data[1] = 0` should work for `x :: A{<:Vector}` and `x :: B{<:SVector}`. It even works for `x :: A{<:SVector}` so you don’t need to define the struct `B`. This “magic” is implemented in [https://github.com/jw3126/Setfield.jl](https://github.com/jw3126/Setfield.jl)

---

<div class="post-metadata">

**Author:** ![Zach\_Christensen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zach_christensen/32/7220_2.png) [@Zach\_Christensen](https://discourse.julialang.org/u/Zach_Christensen)\
**Post date:** [February 12, 2020, 4:49am UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/11 "2020-02-12T04:49:10Z")

</div>

> [@tomtom](#):
>
> the problem is how to get the best from both worlds (i.e. using a fast, immutable `struct` for mutable vector & using a mutable `struct` for immutable vector) **without defining two custom types**.

I’m still not sure I understand exactly what you’re trying to do. If you want mutable fields then this will allow you to have mutable fields with `SVector`.

```julia
mutable struct MyFields
    field1
    field2
    field3
end

struct MyVectorFields
    fields::TypeWithManyFields
    data::SVector
end

```

You said that `data` will need to be changed for every instance and the fields are going to change too. If they are all changing at the same time then just create a new instance every time they are all changed. In which case this would be fine:

```julia
struct MyVectorFields
    field1
    field2
    field3
    data::SVector
end

```

If you’re concerned with the first example because you are changing `data` a lot more frequently than the rest of your fields and don’t want the overhead of constructing a new instance (which should be small since it’s only two fields), then `data` probably shouldn’t be part of the rest of the data.

It’s difficult to know exactly where the problem lies with any of these solutions without a more concrete example of what you are trying to do.

---

<div class="post-metadata">

**Author:** ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)\
**Post date:** [February 12, 2020, 6:14am UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/12 "2020-02-12T06:14:55Z")

</div>

inspired by your suggestions, I realized that the solution is quite **simple** : instead of calling

```julia
setdata!(obj, x)

```

I should call

```julia
obj = setdata!(obj, x)

```

that’s it! (despite that this calling convention is not idiotmatc)

```julia
### normal & fast immutable struct
struct A{T <: AbstractVector}
    data::T
    others::Int
end

### traits
abstract type IsMutableTrait end
struct Mutable <: IsMutableTrait end
struct Immutable <: IsMutableTrait end
ismutable(::Type{<:SVector}) = Immutable()
ismutable(::Type{<:AbstractVector}) = Mutable()

function setdata!(obj::A{T}, x::T)::A{T} where {T}
    setdata!(ismutable(T), obj, x)
end

function setdata!(::Mutable, obj::A{T}, x::T)::A{T} where {T}
    obj.data .= x
    return obj # ***returns itself***
end

function setdata!(::Immutable, obj::A{T}, x::T)::A{T} where {T}
    newobj = A(x, obj.others)
    return newobj # ***returns a new object***
end

v = A([1, 2], 0)
sv = A(SVector(1, 2), 0)

julia> v = setdata!(v, [3, 4])
A{Array{Int64,1}}([3, 4], 0)

julia> sv = setdata!(sv, SVector(3, 4) )
A{SArray{Tuple{2},Int64,1,2}}([3, 4], 0)

```

in this way, I got the following advantages:

1. only a single (fast, normal, immutable) `struct` is needed; no need to maintain two `struct`s
2. updating a mutable `data` could be done in-place (by `.=`)
3. a new object is needed to be created **only** during updates of the immutable `data`

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [February 12, 2020, 7:11am UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/13 "2020-02-12T07:11:00Z")

</div>

I think what you just came up with is a nice API. That’s how I’d do if I were to do this in a self-contained module.

It’s just a nit-picking, but I think the API

> [@tomtom](#):
>
> instead of calling
> 
> ```julia
> setdata!(obj, x)
> 
> ```
> 
> I should call
> 
> ```julia
> obj = setdata!(obj, x)
> 
> ```

is somewhat non-conventional. Usually in Julia, for API `f!(dest, args...)`, I think you’d expect `dest` to be _guaranteed_ to be mutated. However, your `setdata!` sometimes don’t. I think it’s OK for an internal function. `Base` has something like this; e.g., `grow_to!`. But if you are going to expose it as a public API, maybe it’s confusing?

(BTW, that’s why I’m using a strange `!!` suffix in BangBang.jl. But I don’t think it’s a conventional suffix.)

---

<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:** [February 12, 2020, 7:22am UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/14 "2020-02-12T07:22:41Z")

</div>

> [@tkf](#):
>
> I think you’d expect `dest` to be _guaranteed_ to be mutated.

I wouldn’t. I would expect that it _allows_ `dest` to be mutated, but that’s an option.

> [@tkf](#):
>
> that’s why I’m using a strange `!!` suffix

FWIW, I would be fine with just `!` for this case.

I don’t think that it is common for callers to _depend_ on the contents of an argument being actually mutated. Consider eg

```julia
using LinearAlgebra
A = Matrix(Diagonal(ones(2)))
B = cholesky(A)
rdiv!(A, B)

```

A conforming program couldn’t even tell if `A` was mutated here, since it is `==` to the original.

---

<div class="post-metadata">

**Author:** ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)\
**Post date:** [February 12, 2020, 7:27am UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/15 "2020-02-12T07:27:35Z")

</div>

> [@tkf](#):
>
> is somewhat non-conventional.

yeah… it’s not idiomatic. And it’s the very reason I spent so much time stuck in the problem!!!

maybe I should better rename `setdata!()` as something like `setdataΔ()` to remind myself (and others) of this strange usage.

just for completeness:

```julia
### normal & fast immutable struct
struct A{T <: AbstractVector}
    data::T
    others::Int
end

### traits
abstract type IsMutableTrait end
struct Mutable <: IsMutableTrait end
struct Immutable <: IsMutableTrait end
ismutable(::Type{<:SVector}) = Immutable()
ismutable(::Type{<:AbstractVector}) = Mutable()

function setdataΔ(obj::A{T}, x::T)::A{T} where {T}
    setdataΔ(ismutable(T), obj, x)
end

function setdataΔ(::Mutable, obj::A{T}, x::T)::A{T} where {T}
    obj.data .= x
    return obj
end

function setdataΔ(::Immutable, obj::A{T}, x::T)::A{T} where {T}
    newobj = A(x, obj.others)
    return newobj
end

v = A([1, 2], 0)
sv = A(SVector(1, 2), 0)

v = setdataΔ(v, [3, 4])
sv = setdataΔ(sv, SVector(3, 4) )

julia> v = setdataΔ(v, [3, 4])
A{Array{Int64,1}}([3, 4], 0)

julia> sv = setdataΔ(sv, SVector(3, 4) )
A{SArray{Tuple{2},Int64,1,2}}([3, 4], 0)

```

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [February 12, 2020, 7:57am UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/16 "2020-02-12T07:57:02Z")

</div>

> [@Tamas\_Papp](#):
>
> I don’t think that it is common for callers to _depend_ on the contents of an argument being actually mutated.

Functions like `pop!`, `splice!`, `take!(channel)`, `put!`, etc. depend on mutation.

I’m not sure what you want to point out with `rdiv!` example. It’s docstring says

> Compute A / B in-place and overwriting A to _store the result_.

I’d argue that `rdiv!` method implementation that does not mutate `A` has a bug.

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [February 12, 2020, 8:06am UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/17 "2020-02-12T08:06:54Z")

</div>

> [@Tamas\_Papp](#):
>
> > I think you’d expect `dest` to be _guaranteed_ to be mutated.
> 
> I wouldn’t. I would expect that it _allows_ `dest` to be mutated, but that’s an option.

So do you think it’s OK to add APIs like `push!(::Tuple, _)` and `delete!(::NamedTuple, ::Symbol)` in Base? What about `push!(::StaticVector, _)`? I personally find them strange but if I’m a minority I’m happy to use such APIs as they are _very_ useful.

---

<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:** [February 12, 2020, 8:14am UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/18 "2020-02-12T08:14:00Z")

</div>

> [@tkf](#):
>
> I’d argue that `rdiv!` method implementation that does not mutate `A` has a bug.

Consider the hypothetical

```julia
my_rdiv!(A::AbstractMatrix, J::UniformScaling) = my_rdiv!(A, J.λ)

function my_rdiv!(A::AbstractMatrix, λ::Real)
    λ == 1 ? A : LinearAlgebra.rdiv!(A, λ)
end

```

It may or may not mutate `A`. I am not proposing it as something elegant or efficient, but I think it would be conforming.

> [@tkf](#):
>
> So do you think it’s OK to add APIs like `push!(::Tuple, _)`

No. The method should do what the contract prescribes, and I would expect that after

```julia
push!(collection, item)
@assert item ∈ collection

```

holds.

My point is very simple: all I am saying that **if the method actually does what it promises, whether it mutates a given argument is irrelevant (as long as that wasn’t promised)**. Eg if the recommended way to use a method is

```julia
result2 = buffered_calculation!(result, arguments)

```

then the method could have `result === result2` and overwrite it (eg for `Array`) or make a new one (`SArray`). As long as this is only conditional on the type, the compiler can deal with it just fine.

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [February 12, 2020, 8:25am UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/19 "2020-02-12T08:25:39Z")

</div>

So you are just saying that when “do nothing” is the correct answer, the caller should expect the argument is not mutated (e.g., `sort!([1, 2, 3])`). I agree, of course. I guess you missed my initial point. It was that it’s _not_ possible to define (say) `push!` semantics on immutable corrections like tuples; hence the weird suffix.

---

<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:** [February 12, 2020, 8:30am UTC](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465/20 "2020-02-12T08:30:21Z")

</div>

To be fair, I think you are missing my point too: all I am saying is that my interpretation is that `!` _allows_ a specific argument to be mutated, but does not _require_ it _per se_.

For `push!`, the requirement for mutating the collection comes from the fact that it should contain item.

[Next page](https://discourse.julialang.org/t/how-to-design-with-immutable-and-also-mutable-type/34465.md?page=2)
