caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Romain Bardou <bardou@lsv.ens-cachan.fr>
To: Goswin von Brederlow <goswin-v-b@web.de>
Cc: caml-list@inria.fr
Subject: Re: [Caml-list] Wish: mutable variant types, equivalence with records
Date: Mon, 26 Mar 2012 10:41:00 +0200	[thread overview]
Message-ID: <4F702B9C.30302@lsv.ens-cachan.fr> (raw)
In-Reply-To: <87fwcx6ejm.fsf@frosties.localnet>

Le 24/03/2012 19:26, Goswin von Brederlow a écrit :
> 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<name>  =<Constructor>  of [mutable]<type>[: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

Hello,

I have been wishing for this for a long time. Mainly because it's just 
tedious to declare a record for each constructor. Too often do I start 
with constructors with a low argument count (say 1 to 3) and find that I 
have to add new arguments. At some point I have so many arguments that I 
really have to declare the record, and thus rewrite all the relevant 
parts of the code.

I would add that it would be convenient for me to be able to name only 
*some* of the arguments. For instance :

type t = Sum of pos: Lexing.position * t * t

I would access the anonymous arguments using pattern-matching as usual, 
and use ".pos" as a shortcut sometimes.

Unifying records and sums is great, unifying tuples at the same time 
seems even better to me. The OPA language (of Mlstate) does this, if I'm 
not mistaken.

Cheers,

-- 
Romain Bardou

      parent reply	other threads:[~2012-03-26  8:41 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-24 18:26 Goswin von Brederlow
2012-03-24 18:32 ` Lukasz Stafiniak
2012-03-24 18:39   ` Lukasz Stafiniak
2012-03-24 18:42     ` Lukasz Stafiniak
2012-03-25 22:45       ` Goswin von Brederlow
2012-03-24 18:42 ` Jonathan Protzenko
2012-03-24 18:45 ` Wojciech Meyer
2012-03-24 18:59   ` Lukasz Stafiniak
2012-03-29 22:46   ` François Bobot
2012-03-30 12:16     ` Goswin von Brederlow
2012-03-30 15:00       ` François Bobot
2012-03-31 15:52         ` Goswin von Brederlow
2012-03-31 19:17     ` Alain Frisch
2012-03-26  8:41 ` Romain Bardou [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4F702B9C.30302@lsv.ens-cachan.fr \
    --to=bardou@lsv.ens-cachan.fr \
    --cc=caml-list@inria.fr \
    --cc=goswin-v-b@web.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).