# How to deal with inconsistent objects due to mutation

**URL:** https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960
**Category:** General Usage
**Tags:** design
**Created:** [March 16, 2022, 11:45am UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960 "2022-03-16T11:45:46Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)
#### Post date: [March 16, 2022, 11:45am UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/1 "2022-03-16T11:45:46Z")

</div>

This is a bit of a basic philosophical question about type and API design. I would love the input of more experienced coders, since I suspect I might be approaching my problem wrong.

I have a type in essence similar to:

```julia
struct Wrapper
    v::Vector{Int}
    length::Int
end

```

The field `length` should equal `length(v)` for consistency. This is a toy example, but in the real world `length` is a bunch of extra fields that should be _consistent_ with field `v`. Moreover, the API requires that the user can access field `v`, so I have an exported `vector(p::Wrapper) = p.v`

The problem is that I have no way to forbid that the user does `push!(vector(p), 1)`, which breaks the internal consistency of `p`. I see a number of options, all of which are very bad for performance. Is there a standard approach to deal with this problem in Julia?

---

<div class="post-metadata">

### Author: ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)
#### Post date: [March 16, 2022, 11:48am UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/2 "2022-03-16T11:48:37Z")

</div>

My approach would be to not allow the user to access `v`. Or to put it generally, do not expose mutable fields to the user if the field’s value have invariants.

You can consider making `Wrapper` an `AbstractVector{Int}` and implement a few basic mutating methods for it, where you in the implementation make sure that the two fields are syncronized.

---

<div class="post-metadata">

### Author: ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)
#### Post date: [March 16, 2022, 11:51am UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/3 "2022-03-16T11:51:33Z")

</div>

What if the user _needs_ read access of `v`? Shouldn’t we have some form of `ImmutableVector` wrapper in Julia?

---

<div class="post-metadata">

### Author: ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)
#### Post date: [March 16, 2022, 11:52am UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/4 "2022-03-16T11:52:31Z")

</div>

When would the user need that? Surely they can just access it through `Wrapper`’s interface?

---

<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: [March 16, 2022, 11:52am UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/5 "2022-03-16T11:52:36Z")

</div>

Another alternative could be create a wrapper for `v` for which `push!` and other operations are not allowed, such as:

```julia
julia> struct MyVec{T} <: AbstractVector{T}
           v::Vector{T}
           length::Int
       end

julia> Base.length(v::MyVec) = v.length

julia> Base.size(v::MyVec) = (1,)

julia> Base.getindex(v::MyVec,i) = getindex(v.v,i)

julia> Base.push!(v::MyVec,val) = error("Cannot push to v")

julia> v = MyVec{Int}([1,2,3],3)
1-element MyVec{Int64}:
 1

julia> push!(v,1)
ERROR: Cannot push to v
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:33
 [2] push!(v::MyVec{Int64}, val::Int64)
   @ Main ./REPL[5]:1
 [3] top-level scope
   @ REPL[18]:1

```

---

<div class="post-metadata">

### Author: ![jbrea](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jbrea/32/3879_2.png) [@jbrea](https://discourse.julialang.org/u/jbrea)
#### Post date: [March 16, 2022, 11:55am UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/6 "2022-03-16T11:55:25Z")

</div>

> What if the user needs read access of v? Shouldn’t we have some form of ImmutableVector wrapper in Julia?

If the vectors aren’t too large you could use StaticArrays.jl instead.

---

<div class="post-metadata">

### Author: ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)
#### Post date: [March 16, 2022, 11:58am UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/7 "2022-03-16T11:58:52Z")

</div>

Thanks everyone! Ok, so the consensus seems to be to not provide direct API access to any mutable field.  
I’d like to note that other standard types, e.g. `SparseMatrixCSC`, have the same problem. They do provide direct API access to mutable fields (`nonzeros` for example), and tinkering with them can wreck your SparseMatrix object. It seems to me like it is a genuine problem that we don’t have a very good solution for, would you agree?

EDIT: in other words, it seems to me Julia has more mechanisms for performance than safety

---

<div class="post-metadata">

### Author: ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)
#### Post date: [March 16, 2022, 12:02pm UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/8 "2022-03-16T12:02:04Z")

</div>

I’m not sure it’s a _problem_, really, as long as there is a social convention that the fields of a struct are private and should not be changed or relied on, unless explicitly documented.

It’s nice that users _can_ mess with internal types if they want, and is willing to bear the risk. It allows extension of other people’s types.

Relevant:

- [Style Guide · The Julia Language](https://docs.julialang.org/en/v1/manual/style-guide/#Prefer-exported-methods-over-direct-field-access)
- [Accessing type internal fields in package interfaces](https://discourse.julialang.org/t/accessing-type-internal-fields-in-package-interfaces/70263)

Edit: But yes, I agree, Julia’s approach of telling people to not mess with internal fields as opposed to _forcing_ people by actually making them inaccessible does prioritize performance (and extensibility) over safety. I think it’s nice still.

---

<div class="post-metadata">

### Author: ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)
#### Post date: [March 16, 2022, 12:07pm UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/9 "2022-03-16T12:07:33Z")

</div>

How do “safe-by-design” languages deal with this? I am familiar with the functional approach that forbids in-place mutations of anything, but that can be unrealistic for performance. Are there not other approaches whereby one can _lock_ a field (make it immutable to the user) somehow?

(Perhaps what I need is to write such a Lock wrapper for my case…)

---

<div class="post-metadata">

### Author: ![pfitzseb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pfitzseb/32/45566_2.png) [@pfitzseb](https://discourse.julialang.org/u/pfitzseb)
#### Post date: [March 16, 2022, 12:10pm UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/10 "2022-03-16T12:10:02Z")

</div>

Note that there’s no way to prevent a sufficiently motivated user from mutating the internals of any object. You can try making it harder (e.g. with the `push!`/`setindex!` overloads suggested above), but ultimately you just need to properly document what users are allowed to do.

---

<div class="post-metadata">

### Author: ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)
#### Post date: [March 16, 2022, 12:10pm UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/11 "2022-03-16T12:10:53Z")

</div>

In some languages you have to explicitly mark types and/or fields as public, otherwise they will not be visible outside the module they are defined in.

---

<div class="post-metadata">

### Author: ![josuagrw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/josuagrw/32/1015_2.png) [@josuagrw](https://discourse.julialang.org/u/josuagrw)
#### Post date: [March 16, 2022, 12:11pm UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/12 "2022-03-16T12:11:23Z")

</div>

If a field should be immutable, then you should use an immutable type for that field.

---

<div class="post-metadata">

### Author: ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)
#### Post date: [March 16, 2022, 12:14pm UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/13 "2022-03-16T12:14:46Z")

</div>

> If a field should be immutable, then you should use an immutable type for that field.

I think this is the right answer for my specific case. I want to use an `AbstractVector` type that is (1) immutable and (2) does not need to know it’s length in advance (unlike StaticArrays). We don’t have such an `ImmutableArray` type in Base, right?

---

<div class="post-metadata">

### Author: ![josuagrw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/josuagrw/32/1015_2.png) [@josuagrw](https://discourse.julialang.org/u/josuagrw)
#### Post date: [March 16, 2022, 12:23pm UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/14 "2022-03-16T12:23:57Z")

</div>

I assume the main goal is to avoid allocating multiple copies of the data. That’s why you want to mutate the array.

You could do this:

```julia
using StaticArrays

struct MyVector{N}
    v::SizedVector{N}
    n::Int
end

push!(m::MyVector{N}, x) where N =
    MyVector(SizedVector{N+1}(push!(m.v.data, x)), N+1)

```

The `SizedVector` type is protected from resizing by its implementation.

EDIT: Of course this is a bit absurd. You would probably also have an inner constructor and probably not have n as a field at all…

---

<div class="post-metadata">

### Author: ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)
#### Post date: [March 16, 2022, 12:26pm UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/15 "2022-03-16T12:26:10Z")

</div>

You are right there is not yet immutable arrays in Base. See [https://github.com/JuliaLang/julia/pull/44381](https://github.com/JuliaLang/julia/pull/44381). There was some hope it would be in Julia 1.8, but it’s been pushed. Hopefully in 1.9 or 1.10, so sometime in 2022.

---

<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: [March 16, 2022, 7:47pm UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/16 "2022-03-16T19:47:39Z")

</div>

This immutable array business is quite tantalizing, but also a bit mysterious. It could be good for parallelism, automatic differentiation, safety, ‘reasoning about’ stuff, etc. as far as I’ve heard.

But how does it actually work? How can it be efficient, and how could it impact the Julia ecosystem? Has anyone _mused_ about any of these questions anywhere?

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [March 16, 2022, 10:38pm UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/17 "2022-03-16T22:38:35Z")

</div>

I sincerely would go the completely opposite direction and do not have the other fields, instead they are computed on the fly from the vector and cannot ever disagree with it, but maybe this only works for the toy example.

---

<div class="post-metadata">

### Author: ![goerch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerch/32/29122_2.png) [@goerch](https://discourse.julialang.org/u/goerch)
#### Post date: [March 16, 2022, 10:47pm UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/18 "2022-03-16T22:47:47Z")

</div>

My 2 cents: you can’t have it all (i.e. allowing access to internal data and keeping consistency).

---

<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: [March 17, 2022, 6:29am UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/19 "2022-03-17T06:29:05Z")

</div>

> [@pablosanjose](#):
>
> (2) does not need to know it’s length in advance (unlike StaticArrays)

If you’re not keen on compiling per vector size, then you need your wrapper to hold a pointer to something on the heap. For pointing to an immutable vector of variable size, you could annotate `v` with an abstract type like `v::NTuple{N, Int} where N` or `v::SVector{N,Int} where N ` (from StaticArrays.jl).

If keeping the length the same is all you really need, you could also make `v` a Nx1 `Matrix`. That’ll get around the `push!`/`insert!`/`deleteat!`/`pop!` methods for `AbstractVector`.

---

<div class="post-metadata">

### Author: ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)
#### Post date: [March 17, 2022, 7:58am UTC](https://discourse.julialang.org/t/how-to-deal-with-inconsistent-objects-due-to-mutation/77960/20 "2022-03-17T07:58:42Z")

</div>

Thanks for all the suggestions! I think that, until we have ImmutableArrays, I will follow what I feel is the standard Julian approach, i.e. to put an emphasis on performance, and place on the user the responsibility of not messing with object properties in undocumented ways. Computing (instead of storing) the invariants is not an option in my case. And as @pfitzseb mentioned, any attempt at ensuring consistency is never going to be bulletproof without explicit language support.
