On Tue, Mar 25, 2014 at 6:32 PM, Keith Mason <[email protected]> wrote:
> Why not foos[1].bar instead of the 'convert / unsafe_load' code?
Because I wanted to show that the values are stored inline, rather than
heap allocated. That may have been clear to me but perhaps not so clear to
anyone else. Consider, for comparison, the mutable version of the same code:
julia> type Foo
bar::Int
baz::Float64
end
julia> foos = Array(Foo,10)
10-element Array{Foo,1}:
#undef
#undef
#undef
#undef
#undef
#undef
#undef
#undef
#undef
#undef
julia> foos[1] = Foo(1,2)
Foo(1,2.0)
julia> p = convert(Ptr{Int}, pointer(foos))
Ptr{Int64} @0x00007ff47514f030
julia> unsafe_load(p,1)
140687914392808
julia> unsafe_load(p,2)
0
There are a number of differences, all stemming from the fact that mutable
Foos must be individually heap allocated, rather than stored inline in the
array. Thus, an uninitialized slot in an Array{Foo} is #undef (null
pointers under the hood), rather than whatever junk happens to be the
memory that is allocated, as happens in the immutable version. When you get
the first 64-bit value at the offset of the array, you get a pointer to a
heap-allocated Foo value, rather than the data of that Foo value. The next
value after that is a null pointer. We can poke a bit further by following
the pointer:
julia> pp = convert(Ptr{Int},unsafe_load(p,1))
Ptr{Int64} @0x00007ff475295ce8
julia> unsafe_load(pp,1)
140687913054080
julia> unsafe_load(pp,2)
1
julia> unsafe_load(pp,3)
4611686018427387904
The first 64-bit value at the pointer location are a type tag indicating
what kind of value this thing is; the second and third 64-bit blobs are the
values of the .bar and .baz fields.