Version française
Home     About     Download     Resources     Contact us    

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

Browse thread
[Caml-list] Marshalling unknown types
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: 2004-01-26 (08:22)
From: Alex Baretta <alex@b...>
Subject: [Caml-list] Marshalling unknown types
I would like Caml breeders and Caml riders to comment on the following 
issue: the need to type-safe unmarshalling of datastructures and the way 
to achieve it.

The Marshal module appropriately provides polymorphic functions as
 > val from_string : string -> 'a (* Offset parameter omitted *)

Such polymorphism is unable to provide static type safety. I would be 
happy with runtime type safety: in other words, I'd be happy with an 
exception being thrown at runtime if a datastructure is unmarshalled to 
the wrong runtime type. The obvious way to do this is the following.

module Type_safe_marshal = struct
   let to_string (ex:exn) = Marshal.to_string ex []
   let from_string s = raise (Marshal.from_string s 0)

module Foobar_marshal = struct
   open Type_safe_marshal
   type foobar = Foo of int | Bar of string
   exception Foobar of foobar

   let to_string (x:foobar) = to_string (Foobar x)
   let from_string s = try raise (from_string s) with
     | Foobar x -> x

open Foobar_marshal
let foo1 = foo 1
let what = from_string (to_string foo1)

Obviously this does not work. For some reason, as someone already 
pointed out, pattern matching does not work on unmarshalled exceptions. 
When the above code is sent to the toplevel interpreter I get the 
following output.

module Type_safe_marshal :
   sig val to_string : exn -> string val from_string : string -> 'a end

module Foobar_marshal :
     type foobar = Foo of int | Bar of string
     exception Foobar of foobar
     val to_string : foobar -> string
     val from_string : string -> foobar
val foo1 : Foobar_marshal.foobar = Foo 1
Exception: Foobar_marshal.Foobar _.

I'm sure that there are excellent reasons why this should occur. So, I 
tried a less obvious means of achieving runtime type safety for 
unmarshalled objects.

module Type_safe_marshal_2 = struct
   let to_string (f:unit -> 'a) = Marshal.to_string f [Marshal.Closures]
   (* f is a function which builds and throws an appropriate exception *)
   let from_string s () = Marshal.from_string s 0 ()

module Foobar_marshal_2 = struct
   open Type_safe_marshal_2
   type foobar = Foo of int | Bar of string
   exception Foobar of foobar

   let raise_foobar x () = raise (Foobar x)
   let to_string x = to_string (raise_foobar x)
   let from_string s = try from_string s () with
     | Foobar x -> x

open Foobar_marshal_2
let foo1 = Foo 1
let what = from_string (to_string foo1)
let _ = Printf.eprintf "Hey, I managed to build \"what\" alright!\n"

Here I try to build and raise the exceptions at unmarshalling time by 
actually marshalling closures of functions know how to throw an 
exception containing the datastructure I wish to marshal. However, this 
code cannot be run in the toplevel. This is what it says:

Exception: Invalid_argument "output_value: abstract value".

Apparently, closures built by the toplevel compiler cannot be 
marshalled. So let's try with ocamlc. I placed the above code in and compiled it with ocamlc.

$ ocamlc -o foobar_marshal
$ ./foobar_marshal
Fatal error: exception Foobar_marshal.Foobar_marshal_2.Foobar(1)

I can find no reasonable explanation for this behavior. I realize that 
exceptions are nasty beasts and that the marshalling functions were not 
meant for them, but in this case, the exception is only built and raised 
*after* unmarshalling occurs, so I don't see why pattern matching should 


All this said, O great Camlers, what is your verdict? If my approach is 
sound, how can I fix my code to make it work? If my approach is 
misguided, how should type-safe unmarshalling be achieved?

To unsubscribe, mail Archives:
Bug reports: FAQ:
Beginner's list: