# Small changes on large arrays of custom types: mutable or immutable? shallow or deepcopy?

**URL:** <https://discourse.julialang.org/t/small-changes-on-large-arrays-of-custom-types-mutable-or-immutable-shallow-or-deepcopy/82335>\
**Category:** Performance\
**Tags:** mutable-structure, copy, deepcopy\
**Created:** [June 6, 2022, 6:23pm UTC](https://discourse.julialang.org/t/small-changes-on-large-arrays-of-custom-types-mutable-or-immutable-shallow-or-deepcopy/82335 "2022-06-06T18:23:30Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![skraemer](https://avatars.discourse-cdn.com/v4/letter/s/4bbf92/32.png) [@skraemer](https://discourse.julialang.org/u/skraemer)\
**Post date:** [June 6, 2022, 6:23pm UTC](https://discourse.julialang.org/t/small-changes-on-large-arrays-of-custom-types-mutable-or-immutable-shallow-or-deepcopy/82335/1 "2022-06-06T18:23:30Z")

</div>

_(I have previously asked this on the New to Julia category, but I think might rather belong here)_

There are a few things somehow all related about the following situation concerning mutability to which I can not find a clear answer.

Consider a custom type

```julia
struct Single # or make mutable?
   a::Int
   b::Int
   # ... and more
end

```

that itself appears in:

```julia
struct DataCollection
   structure::Vector{Single}
   rawdata::Vector{Array} # not same length as structure
end

```

We now expect minor modifications such as:

```julia
function foo!(dc::DataCollection, w::Int)
   # change dc.structure[w].a
   # change rawdata[dc.structure[w].a]
end

```

Further, we expect applications such as:

```julia
dc1 = DataCollection() # make some random DataCollection
foo!(dc1,1) # ... and more operations
dc2 = copy(dc1) # in some way, possibly deepcopy
foo!(dc1,1) # ... but do not change dc2 in any way
foo!(dc2,1) # ... but do not change dc1 in any way

```

What I have so far considered are:

1. make `Single` immutable, and let `foo!` do something like `dc.structure[w] = Single(new_a,old_b,...)`  
→ the `copy` operation then only needs to be a shallow copy
2. make `Single` mutable, and let `foo!` do something like `dc.structure[w].a = new_a`  
→ the `copy` then needs to do a `deepcopy` of `.structure`
3. make `Single` mutable, but _still_ do something like `dc.structure[w] = Single(new_a,old_b,...)`

**Question (a):** When `Single` is `immutable`, is there even a difference between `= copy(dc.structure)` and `= deepcopy(dc.structure)`? In a short test, at least given many fields in `Single`, shallow copying a `Vector` of `mutable Single`’s is indeed significantly faster. This would maybe make (3) much better than (1). The documentation somewhat states that mutable types are hardcopied, though I wonder a bit why, and anyway some more magic apparently happens that I unfortunately do not fully understand.

**Question (b):** Assuming shallow copies of immutable types are actually cheap, then approach (2) still avoids possibly very frequent reinitializations of `Single` type objects. It is also more flexible when dealing with `Single` in yet other functions as one can do things like `for s in dc.structure; s.a = 1; end`. As approach (2) has some advantages, is there some usual approach to best bookkeep these deepcopies at a minimum?

**Question (c):** Are there strict counterexamples how any of (1), (2) or (3) can cause other, serious drawbacks or pitfalls (meaning non-generic _this is bad style_ arguments)

**Question (d):** Only approach (2) would in principle also allow to make `.structure` a `Tuple` in the sense that changing part of it does not necessitate copying the whole `Tuple`. But is this even beneficial?

**Question (e):** If `.structure` instead needs to be `Dict` as some `bar!` may remove some entry; how does `delete!(dc.structure, w)` depend on the mutability of `Single`?

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [June 7, 2022, 9:00am UTC](https://discourse.julialang.org/t/small-changes-on-large-arrays-of-custom-types-mutable-or-immutable-shallow-or-deepcopy/82335/2 "2022-06-07T09:00:46Z")

</div>

This is a fairly complicated example and question with many parts, so excuse me for just commenting on one part that I’m interested in.

AFAIK, the point of mutable types is allowing multiple references to share an instance and its change. If I don’t need a change to be shared, reassigning a reference is sufficient, and the instance can be either mutable or immutable. I lean toward `isbits` types, which are both immutable and contain no references, for performance benefits; mutables and references usually require allocations of data scattered in memory.

Thing is, I do often make a type mutable if I want small changes like changing a field, even if I don’t need the full instance to be shared by multiple references. That’s because there’s a convenient `setfield!` and dot syntax for it. There is a `Setfield.jl` for doing the same thing with an immutable instance, but I didn’t ever figure out how to make it work for an immutable element of an array.

I also don’t know if it is possible for the compiler to implement reassignment of an immutable instance as an edit of a single field’s data, or if it has to make a whole instance from scratch like how it’s written. That would depend a lot on the implementation of immutable instances, and I don’t know how to read LLVM.

---

<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:** [June 7, 2022, 12:30pm UTC](https://discourse.julialang.org/t/small-changes-on-large-arrays-of-custom-types-mutable-or-immutable-shallow-or-deepcopy/82335/3 "2022-06-07T12:30:26Z")

</div>

Unless `Single` has many fields, option 1 is probably the best.

---

<div class="post-metadata">

**Author:** ![Philippe\_Maincon1](https://avatars.discourse-cdn.com/v4/letter/p/ec9cab/32.png) [@Philippe\_Maincon1](https://discourse.julialang.org/u/Philippe_Maincon1)\
**Post date:** [June 7, 2022, 12:56pm UTC](https://discourse.julialang.org/t/small-changes-on-large-arrays-of-custom-types-mutable-or-immutable-shallow-or-deepcopy/82335/4 "2022-06-07T12:56:51Z")

</div>

Let us say you keep `DataCollection` immutable. Immutable means you can not change any of its fields, but there’s a catch:

`Vector` is a mutable container, allocated on the heap: What is immutable in `DataCollection` is the pointer to where on the heap the content of the `Vector` is stored. The catch is you can overwrite all or part of the data in that `Vector`, on the heap.

A shallow copy of a `DataCollection` duplicates this pointer. Overwriting `dc1.structure[w] = Single(...)` will affect `dc1` and `dc2`.

You are OK with that? `copy`. Not OK? `deepcopy`, in which case the vector on the heap is copied to a distinct vector on the heap.
