Are the entries in a vector of immutable structs stored in place, or is there always a pointer to the heap?

Are the entries in a vector of immutable structs stored in place, or
is there always a pointer to the heap?

(Or how can I get Julia to do something equivalent).

I have a question about the interplay between vectors and
mutable/immutable structs.

If I have a vector of mutable structs, then obviously then each entry
in the vector has an independent life in the heap (since the same
object could be in more than one vector, and if I modify a struct
stored in one vector I can see the modifications in another vector).

On the other hand, if I have a vector of immutable structs (of
well-defined size), then there is no need for a pointer to an
independent object - I can store the contents of the struct in
situ. There is no need for independent allocation on the heap.

The question is: does Julia do this, or is there some way to get the
same effect, so that when I push structured but immutable data onto a
vector, it is written into the vector in the same way as if I were to
push an integer onto a vector of integers, and not linked via a
pointer.

Motivation is obviously to avoid allocating heap storage every time I
push a structured something onto a vector.

Thanks,

Sean Matthews

1 Like

Yes.

1 Like

thanks.

But only if they are also isbits, no?

In 1.4+ it is also for structs containing certain type of uinions:

julia> struct Foo
           a::Union{Nothing, Float64}
       end

julia> Base.allocatedinline(Foo)
true
4 Likes

Wait. What changed in 1.4? I thought that efficient arrays of small unions was a thing dating from Julia 0.7 (eg. the whole missing efficiency thing). Did the storage strategy change?

1 Like

Doing the union splitting optimization is orthogonal to how things are stored. And yes, that did change:

1 Like

My understanding was that the struct is still stored inline for non-isbits types, but the contents of the struct may be pointers. Update: this is wrong, see below.

Ah, right, I got confused. I thought of

julia> Base.allocatedinline(Union{Nothing, Float64})
true

which is true in Julia 1.0-1.3. Thank you for the reference, that is cool.

I don’t think so because you would then have to recreate the Julia object holding those structs on getindex. So either the data is stored inline, or you have pointers to structs.

1 Like

You’re right, sorry:

julia> struct Foo . # struct with non-isbits fields
           x::Any
           y::Any
       end

julia> Foo(3,4)
Foo(3, 4)

julia> a = [Foo(3,4)]
1-element Array{Foo,1}:
 Foo(3, 4)

julia> sizeof(a) / sizeof(Int)
1.0

If the fields were stored inline, the size would be 2 pointers (2*sizeof(Int)), not 1.