This site is updated infrequently. For up-to-date information, please visit the new OCaml website at ocaml.org.

Issues with Sexplib (#1)
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
 Date: 2008-11-29 (16:40) From: Dario Teixeira Subject: Issues with Sexplib (#1)
```Hi,

I have found a couple of issues with Sexplib/Type-conv.  I am not sure they
are bugs or features, but to me they come across as unexpected, regardless.
In this message I'll report the first one;  the second follows momentarily.

Consider the Foobar module defined below.  It uses a phantom type to annotate
values of type Foobar.t, defined recursively.  The idea is that constructors
A and C are deemed "basic" while B and D are "complex".  Functions make_basic
and make_complex are used to "freeze" the structure.  Because the complex
phantom value propagates across a structure, one cannot apply make_basic to
a structure that uses any of the complex constructors.  On the other hand,
make_complex can be applied to any structure.

module Foobar:
sig
type foobar_t =
| A
| B
| C of foobar_t
| D of foobar_t
with sexp

type basic_t = [ `Basic ] with sexp
type complex_t = [ `Complex ] with sexp

type 'a t with sexp

val make_a: unit -> [> `Basic ] t
val make_b: unit -> [> `Complex ] t
val make_c: 'a t -> 'a t
val make_d: 'a t -> [> `Complex ] t

val make_basic: [< `Basic ] t -> [ `Basic ] t
val make_complex: [< `Basic | `Complex ] t -> [ `Complex ] t
end =
struct
type foobar_t =
| A
| B
| C of foobar_t
| D of foobar_t
with sexp

type basic_t = [ `Basic ] with sexp
type complex_t = [`Complex ] with sexp

type 'a t = foobar_t with sexp

let make_a () = A
let make_b () = B
let make_c foobar = C foobar
let make_d foobar = D foobar

let make_basic x = x
let make_complex x = x
end

So far so good; now consider the code below, which serialises and then
unserialises a value of type Foobar.t.  Note how a "complex" structure
can be unserialised as "basic" without any consequences.  Therefore, the
(de)serialisation process can be used to circumvent the restrictions imposed
by the phantom type.

open Foobar

let foobar = make_complex (make_c (make_b ()))

let doc =
let sexp = sexp_of_t sexp_of_complex_t foobar in
let str = Sexplib.Sexp.to_string_hum sexp
in print_endline str;
let sexp2 = Sexplib.Sexp.of_string str in
let doc = t_of_sexp basic_t_of_sexp sexp2
in doc

The resulting types are:

val foobar : Document.Foobar.complex_t Document.Foobar.t    (* Complex *)
val doc : Document.Foobar.basic_t Document.Foobar.t         (* Basic *)

I understand that phantom types have only a compile-time significance,
with no runtime expression at all (hence their name).  Therefore, it's not
altogether surprising that the S-expression builder would simply ignore them.
Still, is there a way to make them explicit in the serialised data, such
that the unserialiser would cause a runtime error in the above example?
Note that the serialiser is already passed sexp_of_complex_t though it
doesn't seem to put it into any actual use.