Version française
Home     About     Download     Resources     Contact us    
Browse thread
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: -- (:)
From: Dario Teixeira <darioteixeira@y...>
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.

Thanks for your time!
Best regards,
Dario Teixeira