# Are immutable struct really immutable?

Hi,

I recently realised that it is possible to edit the entries of an immutable struct as long as they are arrays. For example, by using the code:

``````struct MyStruct
Y::Array{Float64,1}
end

# Define A
A = MyStruct(ones(10));

# Update A.Y
A.Y .+= rand(10);
``````

I would like to understand why this is permitted. Working with an immutable struct, I would have expected to get an error (or at least a warning).

2 Likes

The immutability isnâ€™t recursive, but instead a property of the type itselfâ€¦ So its children are free to be mutable, hence you can put a mutable type (Vector in this case) into an immutable type and happily mutate them.

5 Likes

Right, but what is the advantage of a mutable struct vs an immutable struct if you can still mutate its elements? (I understand it does not work for all types, but it does work for many).

Your struct `Y` is indeed immutable. Itâ€™s really just the pointer to an array that lives somewhere else on the heap, and that pointer canâ€™t change (i.e. it canâ€™t point to a different array). You can however modify the values in the array (to an extent), since itâ€™s not actually in your struct.

So while you can write `A.Y .+= rand(10)`, you cannot write `A.Y = rand(10)`, since that would be create a new array and try to change what `Y` points to.

The array that `Y` points to lives on the heap, not the stack, and you donâ€™t get the advantages that come with living on the stack.

6 Likes

That you canâ€™t mutate itâ€™s fields?
try:

``````A.Y = rand(10);
``````

Thank you! This is clearer now.

However, I still have a doubt. Is there a way to recursively apply the immutability to struct elements?

Maybe try using an `SArray` (from the `StaticArrays` package) rather than an `Array`.

1 Like

Note that while `StaticArray`s are indeed static and immutible, they are designed primarily for linear algebra efficiency on small arrays, not necessarily for â€śprotectingâ€ť their contents. You might notice unnecessarily long compile times if you use them.

Julia, being true to its open nature, does not have any concept of â€śprivacyâ€ť, even the immutability of `struct` is more for memory management than for immutability for its own sake.

If you want, you can build a custom immutable array type really easily

``````struct LockArray{T,N,V<:AbstractArray{T,N}} <: AbstractArray{T,N}
data::V
end

Base.size(v::LockArray) = size(v.data)
Base.getindex(v::LockArray{T,N}, i::Vararg{Int,N}) where {T,N} = v.data[i...]
function Base.setindex!(v::LockArray{T,N}, x, i::Vararg{Int,N}) where {T,N}
throw(ArgumentError("Don't touch my array!!"))
end
``````
``````julia> v = LockArray(rand(3,3,3));

julia> typeof(v)
LockArray{Float64,3,Array{Float64,3}}

julia> v[1,1,1] = Inf
ERROR: ArgumentError: Don't touch my array!!
Stacktrace:
[1] setindex!(::LockArray{Float64,3,Array{Float64,3}}, ::Float64, ::Int64, ::Int64, ::Int64) at /home/msavas200/src/scrap.jl:9
[2] top-level scope at none:0
``````

More likely however, youâ€™re much better off just not worrying about it at all.

3 Likes

Thank you!

`StaticArrays` might be useful for part of what I am doing (a forecasting package). However, I still want to make some of the elements of my structures to be private - at least for the sake of debugging.

It is probably a silly question, but: why do you need to define `Base.size` and `Base.getindex`? Isnâ€™t `Base.setindex!` enough to make it private?

Itâ€™s just the minimal interface to define an `AbstractArray` type. (In this case you are basically just telling it that the field you want to access is called `data`.)

Seriously though, nobody does this for debugging, I encourage you to save yourself some grief and just not worry about it. Be free!

You probably donâ€™t want to use StaticArrays for forecasting, they are really designed for small arrays. If you try using them on giant arrays, the compiler will melt your CPU. (Though, depending on what you are doing, you might have an application for large `Array`s of `StaticArray`s.)

An immutable struct can be mutated because `typeof(X)` is mutable, so `typeof(X).mutable = true` works. Butâ€¦ donâ€™t do this .

7 Likes

@ExpandingMan Thank you for the suggestions. I might be overthinking it!

@ChrisRackauckas Yeah I do not like it either, it looks odd!

1 Like

Just FYI, I asked a similar question to this on StackOverflow when I was first starting out with Julia.

2 Likes