Command line handling categories
I/O, Modules and System Interface
Serialization
Platform
Miscellaneous

Serialization [XL]

XL CLAIRE distribution comes with the module Serialize that provide generic mechanism (using CLAIRE reflection) for writing/reading CLAIRE data structures to/from a communication port. The ability to convert a data structure to a binary stream can be used for Inter Process Communication (IPC) to exchange objects over a network or to store on the hard disk a set of object that belong to a user session. For instance :
 b :: blob!()
 (serialize(b12), serialize(blist(12)))
 (assert(unserialize(b= 12)
 (assert(unserialize(b= list(12))
The example above illustrates the simple case when the serialized data represent a primitive object (an integer and a list with an integer), sometimes we need to serialize a tree of objects having relations one to each other in a single step and we would like the serialize process to be recursive :
 A <: ephemeral_object()
 B <: ephemeral_object(a:A)

 b :: blob!()
 (serialize(bfalseB(a = A())))
 (assert(known?(aunserialize(b))))
We use a serialize restriction that take a top? flag that tell whether the serialization should be simple (when top? is true) or recursive (when top? is false). By default serialize in non-recursive :
 serialize(bx<=> serialize(bfalsex)
When used recursively, serialize will traverse the object relation such to serialize related objects. As such it would serialize the whole database but it doesn't because named objects (class, property...) are not serialized. When a named object is serialized we only save its symbol. It comes the important rule that the process that unserialize a data stream should have in its database all named objects referenced by the data stream (e.g. classes have to be defined in both serializer and unserializer process). The recursion rules are as follow :

Notice that an inverse relation that should exists between a unserialized object and the object database is built during unserialization. Also notice that when an object is unserialized the close constructor is called so that if you serialize an exception, the unserialize process will throw the error (which can be used as an event). Here is a sample method that applies a property with a list of argument (like apply) but does it in a child process. The result is transmitted between the child and the parent through a pipe using serialization facility :
 [fork_apply(p:propertyl:list: any ->
     let s := socketpair() // create a pipe
     in (if forker?()
             // parent process :
             (fclose(s[2]),
             let x := (try unserialize(s[1]) // read the result on the pipe
                         catch any exception!()), // and catch the error if any
                 st := waitpid(forked()) // wait for child termination
             in (if (st[1!= WEXITED & st[3!= 0)
                     error("fork_apply(~S, ~S) failed with ~S"plst),
                 fclose(s[1]),
                 case x (exception close(x)),
                 x))
         else
             // child process :
             (fclose(s[1]),
             try serialize(s[2], apply(pl)) // actually apply
             catch any serialize(s[2], exception!()),
             exit(0),
             0))]
When using serialize over a network one can use the same serialize_context object for the life time of the connection. The context object associates named objects with IDs and the reuse of the same context for multiple serialize operation will be more efficient than creating a new context for each serialized data, for instance :
 let c := client!("host.domain.com"10000),
     ctx := serialize_context!()
 in (while (...)
         (serialize(cctx...),
         ...))


categories Serializationnormal dispatch [XL] Serialize method

serialize(p:port, self:any) -> serialize_context

serialize(p, self) is equivalent to serialize(p, true, self)


categories Serializationnormal dispatch [XL] Serialize method

serialize(p:port, top?:boolean, self:any) -> serialize_context

When top? is true serialize(p,top?,self) writes on p a binary representation of self. When top? is false serialize(p,top?,self) writes on p the object tree starting at self (that is the object self and related objects). The data written on p can then be handle with unserialize to build back the object tree.


categories Serializationnormal dispatch [XL] Serialize method

unserialize(p:port) -> any

unserialize(p) creates an object tree from a serialized data stream (as done with serialize). The calling process should have a correct reading environment, that is the same class definition that was used by the process that serialized the data.