From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail4-relais-sop.national.inria.fr (mail4-relais-sop.national.inria.fr [192.134.164.105]) by walapai.inria.fr (8.13.6/8.13.6) with ESMTP id q2OIgwFT026510 for ; Sat, 24 Mar 2012 19:43:04 +0100 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AusCAOEUbk9KfVM2kGdsb2JhbAAqGrcRA4EFCCIBAQEBCQkNBxQEI4IJAQEBBBICExEIARscAQEDDAYFCw0JFg8JAwIBAgEREQEFARwGDQEHAQEehW+BeQEKKZpfCowWgnGEKz+IdgEFC4skhXkElWCBEY09PYQKgVs X-IronPort-AV: E=Sophos;i="4.73,642,1325458800"; d="scan'208";a="137565960" Received: from mail-ee0-f54.google.com ([74.125.83.54]) by mail4-smtp-sop.national.inria.fr with ESMTP/TLS/RC4-SHA; 24 Mar 2012 19:43:03 +0100 Received: by eekd17 with SMTP id d17so1529223eek.27 for ; Sat, 24 Mar 2012 11:43:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=message-id:date:from:user-agent:mime-version:to:cc:subject :references:in-reply-to:content-type:content-transfer-encoding; bh=FQ6LUzDjO6Wb48Ibn69VDl2NwO5uLxgCNXejgm5WsJQ=; b=WD/fJFk0DCoH7oL8EjkAUeUrRri9O3+KJc+Hs+S8HAOp6krNnGWXPDHR6tQV1TD9wT JdaFTPIbREJnYN5PYmVWf/FDD9Kydyi0HrmWUyCU4u73MxPKqUGySvxEw306NYm+QbXq hl2MozuZ29u6+9t2RR9S2DslrEMn20f+Jl7vaSqzYkUaPm+s5NsPk2WUCrxpy0sc7eGM YDJq8IaNbKT3p8p6DP1Qmz0CDtVaB7rQ3A86+YHjp3VCnpkfqFTmsPn89QP2UGQ+uhMP nXOD8JfTMrnQTTaoFHvjsewBZQYcgbHO51w1KlBmy3HZcQKeLMoHqVyegavGoZrO+xMM cW3g== Received: by 10.14.123.202 with SMTP id v50mr2191992eeh.95.1332614583555; Sat, 24 Mar 2012 11:43:03 -0700 (PDT) Received: from ?IPv6:2a01:e35:2f37:f210:5e26:aff:fe0c:c1d8? ([2a01:e35:2f37:f210:5e26:aff:fe0c:c1d8]) by mx.google.com with ESMTPS id d54sm40468387eei.9.2012.03.24.11.42.55 (version=SSLv3 cipher=OTHER); Sat, 24 Mar 2012 11:43:02 -0700 (PDT) Message-ID: <4F6E15AD.7020000@gmail.com> Date: Sat, 24 Mar 2012 19:42:53 +0100 From: Jonathan Protzenko User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:13.0) Gecko/20120227 Thunderbird/13.0a1 MIME-Version: 1.0 To: Goswin von Brederlow CC: caml-list@inria.fr References: <87fwcx6ejm.fsf@frosties.localnet> In-Reply-To: <87fwcx6ejm.fsf@frosties.localnet> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Subject: Re: [Caml-list] Wish: mutable variant types, equivalence with records Hi, http://caml.inria.fr/mantis/view.php?id=5528 jonathan On 03/24/2012 07:26 PM, Goswin von Brederlow wrote: > Hi, > > consider the code below that counts how often a value is printed. > > The reason why this code works is that the memory layout of a > variant with arguments is identical to a record with the same > types. The only difference is that a variant sets the tag of the memory > block to reflect which constructor it is (here Bar = 0, Baz = 1). > > But the code is fragile. It requires the use of Obj.magic and duplicates > the definitions of bar and baz (once as variant and once as record). If > the type of foo is changed but not the records then bad things will > happen. > > There are ways to do this without Obj.magic: > > type foo = Bar of bar_record | Baz of baz_record > type foo = Bar of int * int ref | Baz of float * int ref > > The first adds an indirection for every access to foo and breaks > matching. The second adds an indirection for every mutable value in the > type. In both cases the extra indirections increase the memory footprint > and runtime. > > > So why not allow mutable in variant types and some equivalence with > records? For example: > > type = of [mutable][:label] [| ...] > > as in: > > type foo = > | Bar of int:i * mutable int:bar_used > | Baz of float:f * mutable int:baz_used > > let use x = > match x with > | Bar bar -> > bar.bar_used<- bar.bar_used + 1 > | Baz baz -> > baz.baz_used<- baz.baz_used + 1 > > let print x = > use x; > match x with > | Bar bar -> Printf.printf "%d\n" bar.i > | Baz baz -> Printf.printf "%f\n" baz.f > > The label is optional and any types in the constructor without label > would be translated into anonymous fields in a record that are > ineaccessible. > > type foo = Foo of int * mutable int:used > > would be equivalent to { _ : int; mutable used : int; } > > Taking it one step wurther one could even allow: > > let bar = { i = 1; bar_used = 0; } > let foo = Bar bar > let foo = let Bar bar = foo in Bar { bar with i = 2; } > > > What do you think? > > MfG > Goswin > > ====================================================================== > module Foo : sig > type foo > val make_bar : int -> foo > val make_baz : float -> foo > val get_used : foo -> int > val print : foo -> unit > end = struct > type foo = Bar of int * int | Baz of float * int > type bar_record = { i : int; mutable bar_used : int; } > type baz_record = { f : float; mutable baz_used : int; } > > let make_bar i = Bar (i, 0) > let make_baz f = Baz (f, 0) > > let use x = > match x with > | Bar _ -> > let (bar : bar_record) = Obj.magic x > in bar.bar_used<- bar.bar_used + 1 > | Baz _ -> > let (baz : baz_record) = Obj.magic x > in baz.baz_used<- baz.baz_used + 1 > > let get_used = function Bar (_, used) | Baz (_, used) -> used > > let print x = > use x; > match x with > | Bar (i, _) -> Printf.printf "%d\n" i > | Baz (f, _) -> Printf.printf "%f\n" f > end;; > > let foo = Foo.make_bar 1 > let used_before = Foo.get_used foo > let () = Foo.print foo > let used_after = Foo.get_used foo > > > >