[gambit-list] problem with serialization/deserialization of structures

Marc Feeley feeley at iro.umontreal.ca
Mon Nov 27 23:38:44 EST 2006


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 27-Nov-06, at 3:45 PM, Alexey Voinov wrote:

>
> Hello.
>
> A friend of mine recently discovered strange behavior in gambit
> interpreter:
>
> $ gsi
> Gambit Version 4.0 beta 20
>
>> (define-structure foo x y)
>> (define a (make-foo 11 22))
>> a
> #<foo #2 x: 11 y: 22>
>> (foo? a)
> #t
>> (define b (u8vector->object (object->u8vector a)))
>> b
> #<foo #3 x: 11 y: 22>
>> (foo? b)
> #f
>> (define c (u8vector->object (object->u8vector a)))
>> c
> #<foo #4 x: 11 y: 22>
>> (foo? c)
> #f
>> (##vector-ref a 0)
> #<type #5 foo>
>> (##vector-ref b 0)
> #<type #6 foo>
>> (##vector-ref c 0)
> #<type #7 foo>
>>
>
> Note, now we have three different types named foo, but can do anything
> useful only with one of them.

This is not a bug, it is a feature.  Let me explain with this  
slightly different example:

(define-structure foo
   x
   y)

(define a (make-foo 11 22))

(with-output-to-file "data"
   (lambda () (write (object->u8vector a))))

(define b (u8vector->object
            (with-input-from-file "data" read)))

(pp (equal? a b)) ==> #f

This code creates an instance of the "foo" record type (i.e. "a"),  
writes a serialized representation to a file, and reads it back as  
the object "b".

A very similar scenario is having a Scheme program X write "a" to a  
file, and having a *different* Scheme program Y read the file to  
create the object "b" (or a process X might send "a" to a process Y  
over the network).  How can Y determine that the type it calls "foo"  
is the same as the type called "foo" in X?  It is important to  
address this issue because we want the system to guarantee that  
operations applied to the incorrect type yield an error.

One possible approach is to say that two record types are the same if  
they have the same name.  This is a poor approach because two record  
types may have the same name by coincidence yet have different  
fields, because they are defined in completely unrelated modules  
(perhaps by different programmers).  Another approach is to say that  
two record types are the same if they have the same name, the same  
number of fields, with the same names.  This is more robust, but it  
fails when say two programmers have chosen the same names and fields  
for completely unrelated purposes (this is more likely when the  
structure is really simple, like a record named "foo" with two fields  
"x" and "y", is the type a 2D point, or the dimensions of a 2D  
matrix, or a dotted pair, or ...?).  Gambit errs on the side of  
safety by treating the types foo in X and Y as different, even if  
they have the same names and fields.

Communication of record types between programs (or between a program  
and a database and back, etc) is achieved in Gambit by having the  
programmer identify explicitly which type he is denoting by giving it  
a "globally" unique name, different from the programmatic name.  The  
type identifier can be any symbol, but generally it is generated by a  
tool like "uuidgen", which is basically a 128 bit random number  
generator.  Here's how you would change the record type definition:

(define-structure foo
   id: foo-6BE0B751-0408-460A-B63A-9A96A843A88E
   x
   y)

With this the program returns #t.  If two programs X and Y need to  
exchange records of this type, they will each contain that record  
definition.

Marc

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.3 (Darwin)

iD8DBQFFa71V//V9Zc2T/v4RArnsAJ95HeDEF2JPPxeLLpGVTzz7bOBcLwCcCHJ1
c2ZTmXKUhk0dfWrIoEaN6ls=
=EQmV
-----END PGP SIGNATURE-----



More information about the Gambit-list mailing list