-----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