Why does Julia's `isbits()` require not only pointer-freeness but immutability?

Although I’m not a native English speaker, the word “isbits” implies pointer-freeness only, i.e. copyable with “memcpy” like POD in c++, dosen’t it?

Aside from wording, why there is no trait that only indicates pointer-freeness (POD) of structures?

For example, I want do

mutable struct T
  a::Int
  b::Float64
end

@assert isPOD(T)  # instead of isbits(T)
reinterpret(T, zeros(UInt8, sizeof(T)*8))

See ?isbits.

Regarding the use of reinterpret, what are you trying to do? If you need to know the memory layout for calling C functions, see this section.

Thank you.

I’m developing a Julia program to edit some binary files in pure Julia without external C program.
I load the file to a Vector{UInt8} and reinterpret it as a Julia’s struct, then modify the sturct (and reinterpret it to Vector{UInt8} again and write back to the file).
The file I’m dealing with has fairly dynamic and nested structure, so I defined a lot of Julia’s structs.

If possible, I’d like to confirm (@assert) that all the Julia’s struct I defined can be properly reinterpreted to Vector{UInt8}, that is, the struct is “plain data” type and contains no reference to other types (but is not required to be immutable).
In Julia, Isn’t there any trait of Types that only indicates whether “plain data” or not?

On 0.6.2, isbits for DataType (the type of Types) is implemented as

isbits(t::DataType) = (@_pure_meta; !t.mutable & (t.layout != C_NULL) && datatype_pointerfree(t))

Maybe you could use last two clauses in your assertion? (use Base.datatype_pointerfree)

It is going to be tricky because of padding / alignment.

I would just write a function that traverses the fields and reads the relevant number of bytes.

the word “isbits” implies pointer-freeness only, i.e. copyable with “memcpy” like POD in c++

There is a subtle difference in the way Julia thinks about POD.

For a mutable struct, copying the value vs passing a pointer to the value can affect the result of the program, because mutating the old copy of the value will not affect the new copy of the value.

In C++, the programmer decides whether to use a value or a pointer. In Julia the compiler decides with no control from the user. If the compiler decided to treat a mutable struct as a value and copy it around, that might change the output of the program. So in Julia only immutable types can be treated that way.

I’m developing a Julia program to edit some binary files in pure Julia without external C program.

Julia does have pointers, so you can read isbits types from a buffer on to the stack:

julia> struct T
         a::Int64
         b::Float64
       end

julia> [(f, fieldoffset(T, i)) for (i, f) in enumerate(fieldnames(T))]
2-element Array{Tuple{Symbol,UInt64},1}:
 (:a, 0x0000000000000000)
 (:b, 0x0000000000000008)

julia> bytes = Vector{UInt8}(sizeof(T) * 2);

julia> p = pointer(bytes);

julia> unsafe_store!(convert(Ptr{T}, p), T(42, 42.0));

julia> unsafe_store!(convert(Ptr{T}, p), T(7, 7.0), 2);

julia> unsafe_load(convert(Ptr{T}, p))
T(42, 42.0)

julia> unsafe_load(convert(Ptr{T}, p), 2)
T(7, 7.0)

julia> string(bytes)
"UInt8[0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x40, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x40]"

You can sprinkle some metaprogramming on top to make it nicer, if you’re doing a lot of it. We have an internal library for working with on-disk data-structures that we should open-source at some point.

3 Likes

Thank you all. Thank you jamli.
I’m convinced why isbits requires immutability. I’m anxious for your library to be open source…

Hopefully, apart from isbits, there would be a trait that only indicates whether “plain data” or not.
Thank you tkoolen for useful information on Base.datatype_pointerfree.
It seems that Julia v0.7 chnges implementation of isbit, and dose not have Base.datatype_pointerfree anymore.