HomeForumSourceResearchGuide
<< back to guide home

Dana can automatically provide a byte array representation of Data instances, as long as the Data type includes only fields of primitive type (including fixed-size arrays of primitive type).

This is done by using the notation dana.serial(x). This operation returns a reference to a byte array containing the contents of x as a stream of bytes. This reference is readable and writable, allowing the individual bytes of a data instance to be modified.

As an example, we could write a data instance to file like this:

data Person {
    char name[50]
    int4 age
    }

Person p = new Person()
p.name = "sam"
p.age = 26
byte stream[] = dana.serial(p)

File fd = new File("myfile.data", File.CREATE)
fd.write(stream)

The byte array that dana.serial() returns has the data instance's fields laid out in plain contiguous memory, with no language-specific format data; the Person type is therefore 54 bytes long in its serial form (50 bytes of the name array, then 4 bytes of the age field).

We could then read our data back from the file by again getting a serial byte array representation, then copying another byte array (read from the file) into that one:

Person p = new Person()
byte stream[] = dana.serial(p)
File fd = new File("myfile.data", File.READ)
stream =[] fd.read(stream.arrayLength)

When doing direct serialisation in this way, it is often good practice to only use explicitly-sized types in your data instance fields. In the above example we have used an int4 rather than an int, because the int type has a variable size in memory depending on the bit-width of the host computer's CPU. If we therefore wrote binary serialised data that included an int on a 64-bit machine, and read that data back on a 32-bit machine, we would then get undefined results.

Finally, note that the serial byte array representation of a data instance is live; it is not a copy of the data instance bytes but is a memory reference to those bytes. Going back to our first example, the following code therefore has exactly the same result:

Person p = new Person()
byte stream[] = dana.serial(p)
p.name = "sam"
p.age = 26

File fd = new File("myfile.data", File.CREATE)
fd.write(stream)

Because the byte array representation is a direct reference to an instance's memory, we can often re-use the same data instance to read or write many serial records in a row.