caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Wish: mutable variant types, equivalence with records
@ 2012-03-24 18:26 Goswin von Brederlow
  2012-03-24 18:32 ` Lukasz Stafiniak
                   ` (3 more replies)
  0 siblings, 4 replies; 14+ messages in thread
From: Goswin von Brederlow @ 2012-03-24 18:26 UTC (permalink / raw)
  To: caml-list

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




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Caml-list] Wish: mutable variant types, equivalence with records
  2012-03-24 18:26 [Caml-list] Wish: mutable variant types, equivalence with records Goswin von Brederlow
@ 2012-03-24 18:32 ` Lukasz Stafiniak
  2012-03-24 18:39   ` Lukasz Stafiniak
  2012-03-24 18:42 ` Jonathan Protzenko
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 14+ messages in thread
From: Lukasz Stafiniak @ 2012-03-24 18:32 UTC (permalink / raw)
  To: Goswin von Brederlow; +Cc: caml-list

On Sat, Mar 24, 2012 at 7:26 PM, Goswin von Brederlow <goswin-v-b@web.de> wrote:
>
> 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?

I'm not sure about mutable but I'd appreciate labels :D


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Caml-list] Wish: mutable variant types, equivalence with records
  2012-03-24 18:32 ` Lukasz Stafiniak
@ 2012-03-24 18:39   ` Lukasz Stafiniak
  2012-03-24 18:42     ` Lukasz Stafiniak
  0 siblings, 1 reply; 14+ messages in thread
From: Lukasz Stafiniak @ 2012-03-24 18:39 UTC (permalink / raw)
  To: Goswin von Brederlow; +Cc: caml-list

On Sat, Mar 24, 2012 at 7:32 PM, Lukasz Stafiniak <lukstafi@gmail.com> wrote:
>
> I'm not sure about mutable but I'd appreciate labels :D

As for syntax, I think that "unboxed anonymous records" would be better.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Caml-list] Wish: mutable variant types, equivalence with records
  2012-03-24 18:39   ` Lukasz Stafiniak
@ 2012-03-24 18:42     ` Lukasz Stafiniak
  2012-03-25 22:45       ` Goswin von Brederlow
  0 siblings, 1 reply; 14+ messages in thread
From: Lukasz Stafiniak @ 2012-03-24 18:42 UTC (permalink / raw)
  To: Goswin von Brederlow; +Cc: caml-list

On Sat, Mar 24, 2012 at 7:39 PM, Lukasz Stafiniak <lukstafi@gmail.com> wrote:
> On Sat, Mar 24, 2012 at 7:32 PM, Lukasz Stafiniak <lukstafi@gmail.com> wrote:
>>
>> I'm not sure about mutable but I'd appreciate labels :D
>
> As for syntax, I think that "unboxed anonymous records" would be better.

For starters, one could make a Camlp4 extension that generates a
record type named "typ_Variant" for a type "typ" and its constructor
"Variant" whose fields are defined as a record. Hmm...

Record unboxing might be handled as an orthogonal issue?

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Caml-list] Wish: mutable variant types, equivalence with records
  2012-03-24 18:26 [Caml-list] Wish: mutable variant types, equivalence with records Goswin von Brederlow
  2012-03-24 18:32 ` Lukasz Stafiniak
@ 2012-03-24 18:42 ` Jonathan Protzenko
  2012-03-24 18:45 ` Wojciech Meyer
  2012-03-26  8:41 ` Romain Bardou
  3 siblings, 0 replies; 14+ messages in thread
From: Jonathan Protzenko @ 2012-03-24 18:42 UTC (permalink / raw)
  To: Goswin von Brederlow; +Cc: caml-list

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<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
>
>
>
>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Caml-list] Wish: mutable variant types, equivalence with records
  2012-03-24 18:26 [Caml-list] Wish: mutable variant types, equivalence with records Goswin von Brederlow
  2012-03-24 18:32 ` Lukasz Stafiniak
  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-26  8:41 ` Romain Bardou
  3 siblings, 2 replies; 14+ messages in thread
From: Wojciech Meyer @ 2012-03-24 18:45 UTC (permalink / raw)
  To: Goswin von Brederlow; +Cc: caml-list

Goswin von Brederlow <goswin-v-b@web.de> writes:

> 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] [| ...]

Please see [1], Alain Frisch has been working recently on implementing
in-line records for constructor arguments.

It's more implementation/design implications than people might think.

[1] http://caml.inria.fr/mantis/view.php?id=5528

-- Wojciech

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Caml-list] Wish: mutable variant types, equivalence with records
  2012-03-24 18:45 ` Wojciech Meyer
@ 2012-03-24 18:59   ` Lukasz Stafiniak
  2012-03-29 22:46   ` François Bobot
  1 sibling, 0 replies; 14+ messages in thread
From: Lukasz Stafiniak @ 2012-03-24 18:59 UTC (permalink / raw)
  To: Wojciech Meyer; +Cc: Goswin von Brederlow, caml-list

On Sat, Mar 24, 2012 at 7:45 PM, Wojciech Meyer
<wojciech.meyer@googlemail.com> wrote:
>
> Please see [1], Alain Frisch has been working recently on implementing
> in-line records for constructor arguments.
>
> It's more implementation/design implications than people might think.
>
> [1] http://caml.inria.fr/mantis/view.php?id=5528

Wow, I hope it gets merged into 4.0 or 4.1! (Sorry for the noise, just
wanted to give the thumbs-up.)

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Caml-list] Wish: mutable variant types, equivalence with records
  2012-03-24 18:42     ` Lukasz Stafiniak
@ 2012-03-25 22:45       ` Goswin von Brederlow
  0 siblings, 0 replies; 14+ messages in thread
From: Goswin von Brederlow @ 2012-03-25 22:45 UTC (permalink / raw)
  To: caml-list

Lukasz Stafiniak <lukstafi@gmail.com> writes:

> On Sat, Mar 24, 2012 at 7:39 PM, Lukasz Stafiniak <lukstafi@gmail.com> wrote:
>> On Sat, Mar 24, 2012 at 7:32 PM, Lukasz Stafiniak <lukstafi@gmail.com> wrote:
>>>
>>> I'm not sure about mutable but I'd appreciate labels :D
>>
>> As for syntax, I think that "unboxed anonymous records" would be better.
>
> For starters, one could make a Camlp4 extension that generates a
> record type named "typ_Variant" for a type "typ" and its constructor
> "Variant" whose fields are defined as a record. Hmm...

Yes please.

That wouldn't eliminate the risk of the two types getting out-of-sync
and save keystrokes.

> Record unboxing might be handled as an orthogonal issue?

MfG
        Goswin

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Caml-list] Wish: mutable variant types, equivalence with records
  2012-03-24 18:26 [Caml-list] Wish: mutable variant types, equivalence with records Goswin von Brederlow
                   ` (2 preceding siblings ...)
  2012-03-24 18:45 ` Wojciech Meyer
@ 2012-03-26  8:41 ` Romain Bardou
  3 siblings, 0 replies; 14+ messages in thread
From: Romain Bardou @ 2012-03-26  8:41 UTC (permalink / raw)
  To: Goswin von Brederlow; +Cc: caml-list

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

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Caml-list] Wish: mutable variant types, equivalence with records
  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-31 19:17     ` Alain Frisch
  1 sibling, 2 replies; 14+ messages in thread
From: François Bobot @ 2012-03-29 22:46 UTC (permalink / raw)
  To: caml-list

On 24/03/2012 13:45, Wojciech Meyer wrote:
> Please see [1], Alain Frisch has been working recently on implementing
> in-line records for constructor arguments.
>
> It's more implementation/design implications than people might think.
>
> [1] http://caml.inria.fr/mantis/view.php?id=5528

In the thread of this proposed feature, there is a remark that inlined 
record and normal record can become competing features. There is also 
the burden that inlined record as proposed can be modified only in 
pattern matching.

But can't we consider that, for a semantic, syntax and typing perspective:

type t =
    | A of string
    | B of ({msg: string; mutable foo:int} as t2)
    | C

is exactly the same thing than:

type t =
    | A of string
    | B of t2
    | C

and t2 = {msg: string; mutable foo:int}


The only difference is that when you create a record of type t2 the tag 
is directly the one of B in the first case and is the default tag for 
record (the first tag if I remember well) in the second case. So in the 
first case applying the constructor B is just the identity.

So you could modify the record of type t2 independently:

val f : t2 -> t2

...
  match x with
   | A s -> ...
   | B ({ msg = ""} as r) -> B (f t2)
   | C
...


The only disadvantage, I see, compared to Alain Frisch's proposition is 
that two records share with difficulty the same field name. But special 
case can be made when we know the record type thanks to the constructor 
eg B {x=...}, C {x=...}.

PS: It's in fact not the same thing for typing in regard of module 
subtyping, if t is made abstract, t2 must be made private. But that can 
be quite useful.

-- 
François

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Caml-list] Wish: mutable variant types, equivalence with records
  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 19:17     ` Alain Frisch
  1 sibling, 1 reply; 14+ messages in thread
From: Goswin von Brederlow @ 2012-03-30 12:16 UTC (permalink / raw)
  To: caml-list

François Bobot <bobot@lri.fr> writes:

> On 24/03/2012 13:45, Wojciech Meyer wrote:
>> Please see [1], Alain Frisch has been working recently on implementing
>> in-line records for constructor arguments.
>>
>> It's more implementation/design implications than people might think.
>>
>> [1] http://caml.inria.fr/mantis/view.php?id=5528
>
> In the thread of this proposed feature, there is a remark that inlined
> record and normal record can become competing features. There is also
> the burden that inlined record as proposed can be modified only in
> pattern matching.
>
> But can't we consider that, for a semantic, syntax and typing perspective:
>
> type t =
>    | A of string
>    | B of ({msg: string; mutable foo:int} as t2)
>    | C
>
> is exactly the same thing than:
>
> type t =
>    | A of string
>    | B of t2
>    | C
>
> and t2 = {msg: string; mutable foo:int}

That would change existing code because B of t2 currently is a Block of
size 1 with tag B and pointer to a record of type t2.

> The only difference is that when you create a record of type t2 the
> tag is directly the one of B in the first case and is the default tag
> for record (the first tag if I remember well) in the second case. So
> in the first case applying the constructor B is just the identity.

Maybe the type of a record could be altered to, at least internally,
include a tag value:

type t = A of string | B of ({msg: string; mutable foo:int} as t2) | C
type t2 = {[B] x : int; }

The inline record would be identical to the external record with tag
value and (t2 :> t) would work even implicitly.

MfG
        Goswin

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Caml-list] Wish: mutable variant types, equivalence with records
  2012-03-30 12:16     ` Goswin von Brederlow
@ 2012-03-30 15:00       ` François Bobot
  2012-03-31 15:52         ` Goswin von Brederlow
  0 siblings, 1 reply; 14+ messages in thread
From: François Bobot @ 2012-03-30 15:00 UTC (permalink / raw)
  To: caml-list

On 30/03/2012 07:16, Goswin von Brederlow wrote:
> François Bobot<bobot@lri.fr>  writes:
>
>> On 24/03/2012 13:45, Wojciech Meyer wrote:
>>> Please see [1], Alain Frisch has been working recently on implementing
>>> in-line records for constructor arguments.
>>>
>>> It's more implementation/design implications than people might think.
>>>
>>> [1] http://caml.inria.fr/mantis/view.php?id=5528
>>
>> In the thread of this proposed feature, there is a remark that inlined
>> record and normal record can become competing features. There is also
>> the burden that inlined record as proposed can be modified only in
>> pattern matching.
>>
>> But can't we consider that, for a semantic, syntax and typing perspective:
>>
>> type t =
>>     | A of string
>>     | B of ({msg: string; mutable foo:int} as t2)
>>     | C
>>
>> is exactly the same thing than:
>>
>> type t =
>>     | A of string
>>     | B of t2
>>     | C
>>
>> and t2 = {msg: string; mutable foo:int}
>
> That would change existing code because B of t2 currently is a Block of
> size 1 with tag B and pointer to a record of type t2.

I don't propose to change how is compiled the second definition. Just 
that if a developer use the first definition in a module he can consider 
that he define t and t2 like in the second definition. The only 
exception is if you use Obj.magic: Obj.magic (B r) == Obj.magic r.
But Obj.magic is not in the semantic I assume.

>
>> The only difference is that when you create a record of type t2 the
>> tag is directly the one of B in the first case and is the default tag
>> for record (the first tag if I remember well) in the second case. So
>> in the first case applying the constructor B is just the identity.
>
> Maybe the type of a record could be altered to, at least internally,
> include a tag value:
Every records already include a tag value, it's just always the same: 
the tag of the first non-constant constructor of a sum type.

>
> type t = A of string | B of ({msg: string; mutable foo:int} as t2) | C
> type t2 = {[B] x : int; }
>
> The inline record would be identical to the external record with tag
> value and (t2 :>  t) would work even implicitly.

I'm not sure that we should make implicit conversion (inference? 
principality?). But that B r is a noop can be very interesting.

If we want to play to extend this feature (perhaps too much) we can play 
with conversion between sum type without cost by allowing Ap to be also 
the identity:


type tpublic =
| A of ({... } as ta)
| B of ({... } as tb)

type tprivate =
| Ap of ta
| Bp of tb
| Cp of ...


Since A,ta and Ap share the same tag the following function is the identity:

let private_of_public = function
   | A x -> Ap x
   | B x -> Bp x

and this one just make one test:

let public_of_private = function
   | Ap x -> A x
   | Bp x -> B x
   | Cp _ -> invalid_arg "public_of_private: non-public value"


And the semantic is the same than if I define the type ta and tb as 
usual record, just the compilation change.

-- 
François Bobot

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Caml-list] Wish: mutable variant types, equivalence with records
  2012-03-30 15:00       ` François Bobot
@ 2012-03-31 15:52         ` Goswin von Brederlow
  0 siblings, 0 replies; 14+ messages in thread
From: Goswin von Brederlow @ 2012-03-31 15:52 UTC (permalink / raw)
  To: Francois Bobot; +Cc: caml-list

François Bobot <bobot@lri.fr> writes:

> On 30/03/2012 07:16, Goswin von Brederlow wrote:
>> François Bobot<bobot@lri.fr>  writes:
>>
>>> On 24/03/2012 13:45, Wojciech Meyer wrote:
>>>> Please see [1], Alain Frisch has been working recently on implementing
>>>> in-line records for constructor arguments.
>>>>
>>>> It's more implementation/design implications than people might think.
>>>>
>>>> [1] http://caml.inria.fr/mantis/view.php?id=5528
>>>
>>> In the thread of this proposed feature, there is a remark that inlined
>>> record and normal record can become competing features. There is also
>>> the burden that inlined record as proposed can be modified only in
>>> pattern matching.
>>>
>>> But can't we consider that, for a semantic, syntax and typing perspective:
>>>
>>> type t =
>>>     | A of string
>>>     | B of ({msg: string; mutable foo:int} as t2)
>>>     | C
>>>
>>> is exactly the same thing than:
>>>
>>> type t =
>>>     | A of string
>>>     | B of t2
>>>     | C
>>>
>>> and t2 = {msg: string; mutable foo:int}
>>
>> That would change existing code because B of t2 currently is a Block of
>> size 1 with tag B and pointer to a record of type t2.
>
> I don't propose to change how is compiled the second definition. Just
> that if a developer use the first definition in a module he can
> consider that he define t and t2 like in the second definition. The
> only exception is if you use Obj.magic: Obj.magic (B r) == Obj.magic r.
> But Obj.magic is not in the semantic I assume.
>
>>
>>> The only difference is that when you create a record of type t2 the
>>> tag is directly the one of B in the first case and is the default tag
>>> for record (the first tag if I remember well) in the second case. So
>>> in the first case applying the constructor B is just the identity.
>>
>> Maybe the type of a record could be altered to, at least internally,
>> include a tag value:
> Every records already include a tag value, it's just always the same:
> the tag of the first non-constant constructor of a sum type.

No it doesn't. Not in its type. It just happens to have a tag 0 in its
memory representation.

Say you have

type r1 = { x : int; }
type Foo = Foo of int | Bar of ({ x : int; } as r2)
type Foo = Foo of ({ x : int; } as r3) | Bar of int

The type r1 and the internal type r2 are not the same. A record of type
r2 would have a tag of 1. Same with r2 and r3, they should be different
types.

>> type t = A of string | B of ({msg: string; mutable foo:int} as t2) | C
>> type t2 = {[B] x : int; }
>>
>> The inline record would be identical to the external record with tag
>> value and (t2 :>  t) would work even implicitly.
>
> I'm not sure that we should make implicit conversion (inference?
> principality?). But that B r is a noop can be very interesting.

The implicit parts would be in matches for example. "match x with B r ->"
would basically just translate to (x :> t2) with the additional check
that the tag is right. Or

let bar = fun i -> {[B] x = i; }
let foo : int -> t = fun i -> bar i

val bar : int -> {[B] x : int; }
val foo : int -> t

On the other hand bar could already be interfered as type int -> t.
It all depends on wether the [<tag>] syntax would be restricted to
inline records in constructors or not.

It probably makes sense to restrict declaring a record with tag to
inline records. Otherwise it might get confusing what value the tag
should actually have.


One other thing: How do you declare a value of such a type?

type r = { x : int; }
type foo = Foo of r | Blub of int
type bar = Bar of { y : int; } | Blubber of int

let myfoo = Foo { x = 0; }
let mybar = Bar { y = 0; }

This would be confusing since the two look identical but do something
quite different.

Maybe the syntax should be more like this:

type r = { x : int; }
type foo = Foo of r | Blub of int
type bar = { Bar y : int; } | Blubber of int

let myfoo = Foo { x = 0; }
let mybar = { Bar y = 0; }

With the constructor actualy inside the record the two cases look
different and it is visually clear that the "Bar" tag is part of the
record while "Foo" is a constructor taking a record as argument.

> If we want to play to extend this feature (perhaps too much) we can
> play with conversion between sum type without cost by allowing Ap to
> be also the identity:
>
>
> type tpublic =
> | A of ({... } as ta)
> | B of ({... } as tb)
>
> type tprivate =
> | Ap of ta
> | Bp of tb
> | Cp of ...
>
>
> Since A,ta and Ap share the same tag the following function is the identity:

Again no, at least it isn't a NOP. The current memory representation of
Ap of ta is incompatible with the representation we want for A of
({... } as ta).

MfG
        Goswin

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Caml-list] Wish: mutable variant types, equivalence with records
  2012-03-29 22:46   ` François Bobot
  2012-03-30 12:16     ` Goswin von Brederlow
@ 2012-03-31 19:17     ` Alain Frisch
  1 sibling, 0 replies; 14+ messages in thread
From: Alain Frisch @ 2012-03-31 19:17 UTC (permalink / raw)
  To: François Bobot; +Cc: caml-list

On 3/30/2012 12:46 AM, François Bobot wrote:
> But can't we consider that, for a semantic, syntax and typing perspective:
>
> type t =
> | A of string
> | B of ({msg: string; mutable foo:int} as t2)
> | C
>
> is exactly the same thing than:
>
> type t =
> | A of string
> | B of t2
> | C
>
> and t2 = {msg: string; mutable foo:int}
>
>
> The only difference is that when you create a record of type t2 the tag
> is directly the one of B in the first case and is the default tag for
> record (the first tag if I remember well) in the second case. So in the
> first case applying the constructor B is just the identity.

It is an interesting idea to give an explicit type to the record 
argument, allowing it to be manipulated as a first-class value.

Instead of requiring an explicit name, one could introduce a syntax to 
refer to the implicit record declaration for a record constructor.  For 
instance, after defining:

  type t =
    | A of string
    | B of {msg:string; mutable foo:int}
    | C

one could refer to the type t/B, which would behave like a normal record 
type (with a runtime representation such that applying B is the identity).

> The only disadvantage, I see, compared to Alain Frisch's proposition is
> that two records share with difficulty the same field name. But special
> case can be made when we know the record type thanks to the constructor
> eg B {x=...}, C {x=...}.

We should rather look for a general solution to record field 
overloading.  I think that changes introduced for GADTs in the typing of 
patterns makes it quite easy to use propagated type information to 
disambiguate between record types sharing the same field names (and 
similarly for sum types sharing the same constructor names).



Alain

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2012-03-31 19:17 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-24 18:26 [Caml-list] Wish: mutable variant types, equivalence with records 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 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).