Arrays of concrete, mutable structs are not stored contiguously in memory


Can someone explain to me why arrays of mutable structs are stored as arrays of pointers in memory? Example:

struct A x::Int32 end
mutable struct B x::Int32 end

a = Array{A}(undef, 2)
b = Array{B}(undef, 2)

println(Signed(pointer(a, 2) - pointer(a))) # Prints 4, because is an array of Int32s
println(Signed(pointer(b, 2) - pointer(b))) # Prints 8, because is an array of pointers

If it knows my struct B must hold a single field of size 4, what stops julia from making contiguous arrays of B structs?


I must be able to read a mutable struct from an array, change its value, and have that change reflected in both the in-hand version and the original version in the array. This is why mutable values are stored as pointers – because you must be able to pass them anywhere and have their effects seen everywhere.

I suppose the reason that the array location in memory can’t serve as the “one actual instance” of the value is that an array can be moved, shrunk, or removed arbitrarily (via push!, pop!, resize!, empty!, etc, or being discovered to be garbage for the GC) but that doesn’t mean all the values it contains can be moved or destroyed. Moving/removing the value would invalidate any pointers to it and enable invalid memory access that would be very difficult to track or mitigate.

Immutable structs, on the other hand, do not have this behavior so are stored inline in arrays.