From mboxrd@z Thu Jan 1 00:00:00 1970 Received: (from majordomo@localhost) by pauillac.inria.fr (8.7.6/8.7.3) id JAA09202; Mon, 26 Jan 2004 09:22:05 +0100 (MET) X-Authentication-Warning: pauillac.inria.fr: majordomo set sender to owner-caml-list@pauillac.inria.fr using -f Received: from concorde.inria.fr (concorde.inria.fr [192.93.2.39]) by pauillac.inria.fr (8.7.6/8.7.3) with ESMTP id JAA09619 for ; Mon, 26 Jan 2004 09:22:04 +0100 (MET) Received: from alex.baretta.com ([213.255.109.130]) by concorde.inria.fr (8.11.1/8.11.1) with ESMTP id i0Q8M4P17904 for ; Mon, 26 Jan 2004 09:22:04 +0100 (MET) Received: from baretta.com (localhost.localdomain [127.0.0.1]) by alex.baretta.com (8.12.8/8.12.8) with ESMTP id i0Q8MDQT013835 for ; Mon, 26 Jan 2004 09:22:14 +0100 Message-ID: <4014CE35.3000503@baretta.com> Date: Mon, 26 Jan 2004 09:22:13 +0100 From: Alex Baretta User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031007 X-Accept-Language: en-us, en MIME-Version: 1.0 To: Ocaml Subject: [Caml-list] Marshalling unknown types Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit X-Loop: caml-list@inria.fr X-Spam: no; 0.00; baretta:01 baretta:01 marshalling:01 riders:01 type-safe:01 val:01 omitted:01 runtime:01 runtime:01 struct:01 foobar:01 struct:01 foobar:01 foo:01 foo:01 Sender: owner-caml-list@pauillac.inria.fr Precedence: bulk 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) end 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 end 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 : sig type foobar = Foo of int | Bar of string exception Foobar of foobar val to_string : foobar -> string val from_string : string -> foobar end 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 () end 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 end 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 marshal_foobar.ml and compiled it with ocamlc. $ ocamlc foobar_marshal.ml -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 fail. *** 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 caml-list-request@inria.fr Archives: http://caml.inria.fr Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/ Beginner's list: http://groups.yahoo.com/group/ocaml_beginners