caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* Re: [Caml-list] Subtyping structurally-equivalent records, or something like it?
@ 2010-05-01 19:55 Dario Teixeira
  2010-05-01 20:01 ` Sylvain Le Gall
  0 siblings, 1 reply; 13+ messages in thread
From: Dario Teixeira @ 2010-05-01 19:55 UTC (permalink / raw)
  To: caml-list, Anthony Tavener

Hi,

>  type kinematic = { lin: Vec.t; ang: Vec.t }
>
> Which I've been using to represent a medley of physical attributes (force, > momentum, velocity, etc.).

I second Stéphane's suggestion of using phantom types; moreover,
I recommend you read an article that discusses them to some detail
and covers their use for precisely this sort of problem:
http://camltastic.blogspot.com/2008/05/phantom-types.html

Cheers,
Dario Teixeira






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

* Re: Subtyping structurally-equivalent records, or something like it?
  2010-05-01 19:55 [Caml-list] Subtyping structurally-equivalent records, or something like it? Dario Teixeira
@ 2010-05-01 20:01 ` Sylvain Le Gall
  2010-05-04 10:33   ` [Caml-list] " AUGER Cédric
       [not found]   ` <4429.86797211251$1272970133@news.gmane.org>
  0 siblings, 2 replies; 13+ messages in thread
From: Sylvain Le Gall @ 2010-05-01 20:01 UTC (permalink / raw)
  To: caml-list

On 01-05-2010, Dario Teixeira <darioteixeira@yahoo.com> wrote:
> Hi,
>
>>  type kinematic = { lin: Vec.t; ang: Vec.t }
>>
>> Which I've been using to represent a medley of physical attributes (force, > momentum, velocity, etc.).
>
> I second Stéphane's suggestion of using phantom types; moreover,
> I recommend you read an article that discusses them to some detail
> and covers their use for precisely this sort of problem:
> http://camltastic.blogspot.com/2008/05/phantom-types.html
>

I really like the use of private type abbreviation for phantom type:
http://ocaml.janestreet.com/?q=node/77

Regards,
Sylvain Le Gall


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

* Re: [Caml-list] Re: Subtyping structurally-equivalent records, or something like it?
  2010-05-01 20:01 ` Sylvain Le Gall
@ 2010-05-04 10:33   ` AUGER Cédric
       [not found]   ` <4429.86797211251$1272970133@news.gmane.org>
  1 sibling, 0 replies; 13+ messages in thread
From: AUGER Cédric @ 2010-05-04 10:33 UTC (permalink / raw)
  Cc: caml-list

I am not expert in Ocaml, is the following the same in terms
of performances as the phantom types?

type kinematic = ...

type force = Force of kinematic
type momentum = Moment of kinematic
...

That is does the constructor introduce an overhead or not?
As there is only one constructor, no overhead should be done in an
optimized compiler.

So general functions should use a kinematic -> [Type]
and a specialized function, force -> [Type] and so on...

I understand this version is not as handy as the phantom types, as we
need to use "match ... with Force f -> ..." or at least "let Force f
= ... in ...", but my question is only in terms of efficiency;
obviously phantom types are more or equally efficient than what I
exposed, but does the reciproque also holds?


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

* Re: Subtyping structurally-equivalent records, or something like it?
       [not found]   ` <4429.86797211251$1272970133@news.gmane.org>
@ 2010-05-04 11:53     ` Sylvain Le Gall
  2010-05-04 12:47       ` [Caml-list] " rossberg
  2010-05-04 13:37       ` Edgar Friendly
  0 siblings, 2 replies; 13+ messages in thread
From: Sylvain Le Gall @ 2010-05-04 11:53 UTC (permalink / raw)
  To: caml-list

On 04-05-2010, AUGER Cédric <Cedric.Auger@lri.fr> wrote:
> I am not expert in Ocaml, is the following the same in terms
> of performances as the phantom types?
>
> type kinematic = ...
>
> type force = Force of kinematic
> type momentum = Moment of kinematic
> ...
>
> That is does the constructor introduce an overhead or not?
> As there is only one constructor, no overhead should be done in an
> optimized compiler.
>

The variants are represented using a block. If you introduce a single
variant, it will create a block that points to kinematic. E.g. "Force of
kinematic" will create a pointer to the kinematic structure. 

Your construction of force and momentum will add a level of indirection
for every use of the kinematic structure.

Phantom type doesn't add a level of indirection and left no trace in the
generated assembler. 

This is not about optimized compiler in this case but about data
representation. Even if you use an optimized compiler (which is not
really the case with ocamlopt), you won't change datastructure
representation to optimize.

Regards,
Sylvain Le Gall


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

* Re: [Caml-list] Re: Subtyping structurally-equivalent records, or something like it?
  2010-05-04 11:53     ` Sylvain Le Gall
@ 2010-05-04 12:47       ` rossberg
  2010-05-04 13:42         ` Sylvain Le Gall
  2010-05-05  9:31         ` Goswin von Brederlow
  2010-05-04 13:37       ` Edgar Friendly
  1 sibling, 2 replies; 13+ messages in thread
From: rossberg @ 2010-05-04 12:47 UTC (permalink / raw)
  To: Sylvain Le Gall; +Cc: caml-list

"Sylvain Le Gall" <sylvain@le-gall.net>:
>
> This is not about optimized compiler in this case but about data
> representation. Even if you use an optimized compiler (which is not
> really the case with ocamlopt), you won't change datastructure
> representation to optimize.

What do you mean? There is no reason in general why a compiler cannot
optimize data representations, and some do in cases like this.

/Andreas


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

* Re: [Caml-list] Re: Subtyping structurally-equivalent records, or something like it?
  2010-05-04 11:53     ` Sylvain Le Gall
  2010-05-04 12:47       ` [Caml-list] " rossberg
@ 2010-05-04 13:37       ` Edgar Friendly
  2010-05-05  9:33         ` Goswin von Brederlow
  2010-05-05 11:10         ` Yaron Minsky
  1 sibling, 2 replies; 13+ messages in thread
From: Edgar Friendly @ 2010-05-04 13:37 UTC (permalink / raw)
  To: caml-list

On 05/04/2010 07:53 AM, Sylvain Le Gall wrote:
> On 04-05-2010, AUGER Cédric<Cedric.Auger@lri.fr>  wrote:
>> type momentum = Moment of kinematic
>>
>> That is does the constructor introduce an overhead or not?
>> As there is only one constructor, no overhead should be done in an
>> optimized compiler.
>>
> This is not about optimized compiler in this case but about data
> representation. Even if you use an optimized compiler (which is not
> really the case with ocamlopt), you won't change datastructure
> representation to optimize.
>
The OCaml compiler *could* special-case this kind of constructor, but as 
there's the syntax:

type momentum = kinematic

Which produces the non-boxed kinematic values, the authors probably 
decided to follow the maxim "Do what the programmer says" for singleton 
variant types.  The question becomes whether phantom types solve this 
problem sufficiently or do we need another type-level construct - 
explicit subtyping relationships.  Forever ago I suggested this to 
achieve a similar goal, and was given yet another solution:

module M : sig
	type momentum
	val of_kin : kinematic -> momentum
	val to_kin : momentum -> kinematic
end = struct
	type momentum = kinematic
	let of_kin x = x
	let to_kin x = x
end

Yes, it's a lot of boilerplate for each type, but you only have to write 
it once (per type), and cross-module inlining should give zero runtime 
cost.  If not, use "%identity", and expose it in the interface.  This 
method is along the lines of Anthony's proposal #4.

E.


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

* Re: Subtyping structurally-equivalent records, or something like it?
  2010-05-04 12:47       ` [Caml-list] " rossberg
@ 2010-05-04 13:42         ` Sylvain Le Gall
  2010-05-04 15:18           ` [Caml-list] " Fabrice Le Fessant
  2010-05-05  9:31         ` Goswin von Brederlow
  1 sibling, 1 reply; 13+ messages in thread
From: Sylvain Le Gall @ 2010-05-04 13:42 UTC (permalink / raw)
  To: caml-list

On 04-05-2010, rossberg@mpi-sws.org <rossberg@mpi-sws.org> wrote:
> "Sylvain Le Gall" <sylvain@le-gall.net>:
>>
>> This is not about optimized compiler in this case but about data
>> representation. Even if you use an optimized compiler (which is not
>> really the case with ocamlopt), you won't change datastructure
>> representation to optimize.
>
> What do you mean? There is no reason in general why a compiler cannot
> optimize data representations, and some do in cases like this.
>

Anyway, if it comes to data alignement and things like that, the
compiler should optimize data representations. But in this case, I
really don't think we are talking about data alignement.

Regards,
Sylvain Le Gall


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

* Re: [Caml-list] Re: Subtyping structurally-equivalent records, or something like it?
  2010-05-04 13:42         ` Sylvain Le Gall
@ 2010-05-04 15:18           ` Fabrice Le Fessant
  0 siblings, 0 replies; 13+ messages in thread
From: Fabrice Le Fessant @ 2010-05-04 15:18 UTC (permalink / raw)
  To: Sylvain Le Gall; +Cc: caml-list

"ocamlopt" does optimize data representation: for example, it can unbox
floats into registers, or into arrays of floats. However, there is a
tradeoff between such optimizations and efficiency: when you do too much
representation optimisation, you might end up performing a lot of tests
because a given type can be represented in multiple formats, and
performing a lot of transformations between the representations,
especially as the FFI (Ocaml interface to C) specifies the
representation of data.

Of course, I am not saying it is not possible to do better: it requires
a lot of energy, the compiler code becomes more complex, and the
improvement on speed is not clear.

--Fabrice


Sylvain Le Gall wrote, On 05/04/2010 03:42 PM:
> On 04-05-2010, rossberg@mpi-sws.org <rossberg@mpi-sws.org> wrote:
>> "Sylvain Le Gall" <sylvain@le-gall.net>:
>>> This is not about optimized compiler in this case but about data
>>> representation. Even if you use an optimized compiler (which is not
>>> really the case with ocamlopt), you won't change datastructure
>>> representation to optimize.
>> What do you mean? There is no reason in general why a compiler cannot
>> optimize data representations, and some do in cases like this.
>>
> 
> Anyway, if it comes to data alignement and things like that, the
> compiler should optimize data representations. But in this case, I
> really don't think we are talking about data alignement.
> 
> Regards,
> Sylvain Le Gall
> 
> _______________________________________________
> Caml-list mailing list. Subscription management:
> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
> 

-- 
Fabrice LE FESSANT
Chercheur, Equipe ASAP
(As Scalable As Possible)
http://www.lefessant.net/

INRIA-Futurs, Bat P - 112
Parc Orsay Université
2-4, rue Jacques Monod
F-91893 Orsay Cedex, FRANCE


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

* Re: [Caml-list] Re: Subtyping structurally-equivalent records, or something like it?
  2010-05-04 12:47       ` [Caml-list] " rossberg
  2010-05-04 13:42         ` Sylvain Le Gall
@ 2010-05-05  9:31         ` Goswin von Brederlow
  2010-05-05 12:12           ` rossberg
  1 sibling, 1 reply; 13+ messages in thread
From: Goswin von Brederlow @ 2010-05-05  9:31 UTC (permalink / raw)
  To: rossberg; +Cc: Sylvain Le Gall, caml-list

rossberg@mpi-sws.org writes:

> "Sylvain Le Gall" <sylvain@le-gall.net>:
>>
>> This is not about optimized compiler in this case but about data
>> representation. Even if you use an optimized compiler (which is not
>> really the case with ocamlopt), you won't change datastructure
>> representation to optimize.
>
> What do you mean? There is no reason in general why a compiler cannot
> optimize data representations, and some do in cases like this.

How could it? At least for any type that is public in a module.

The data representation is part of the ABI. As such it is fixed and can
in no way be optimized by the compiler. Only thing you can do is change
the ABI and define a more optimized representation in the first place.

As example

type foo = { x : int; y : int; }
type bar = Bar of foo

Currently a bar is represented as

foo {
  tag = 0
  size = 2
  field[0] = int(x)
  field[1] = int(y)
}
bar {
  tag = 0 (for Bar)
  size = 1
  field[0] = &foo
}

2 Blocks taking up 5 words.


A better representation would be to combine the two:

bar {
  tag = 0 (for Bar)
  size = 2
  field[0] = int(x) 
  field[1] = int(y) 
}    

A single block of 3 words.

This also works for

type bar = Foo of foo | Blub of foo | Blubber of foo

but not for

type baz = Baz of bar


There are lots of cases where the representation could be improved for
special cases. But ocaml I think only does that for float arrays or
records that only contain floats. But that is a design decision and not
something the compiler can just optimize.

MfG
        Goswin


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

* Re: [Caml-list] Re: Subtyping structurally-equivalent records, or something like it?
  2010-05-04 13:37       ` Edgar Friendly
@ 2010-05-05  9:33         ` Goswin von Brederlow
  2010-05-05 11:10         ` Yaron Minsky
  1 sibling, 0 replies; 13+ messages in thread
From: Goswin von Brederlow @ 2010-05-05  9:33 UTC (permalink / raw)
  To: Edgar Friendly; +Cc: caml-list

Edgar Friendly <thelema314@gmail.com> writes:

> On 05/04/2010 07:53 AM, Sylvain Le Gall wrote:
>> On 04-05-2010, AUGER Cédric<Cedric.Auger@lri.fr>  wrote:
>>> type momentum = Moment of kinematic
>>>
>>> That is does the constructor introduce an overhead or not?
>>> As there is only one constructor, no overhead should be done in an
>>> optimized compiler.
>>>
>> This is not about optimized compiler in this case but about data
>> representation. Even if you use an optimized compiler (which is not
>> really the case with ocamlopt), you won't change datastructure
>> representation to optimize.
>>
> The OCaml compiler *could* special-case this kind of constructor, but
> as there's the syntax:
>
> type momentum = kinematic
>
> Which produces the non-boxed kinematic values, the authors probably
> decided to follow the maxim "Do what the programmer says" for
> singleton variant types.  The question becomes whether phantom types
> solve this problem sufficiently or do we need another type-level
> construct -
> explicit subtyping relationships.  Forever ago I suggested this to
> achieve a similar goal, and was given yet another solution:
>
> module M : sig
> 	type momentum
> 	val of_kin : kinematic -> momentum
> 	val to_kin : momentum -> kinematic
> end = struct
> 	type momentum = kinematic
> 	let of_kin x = x
> 	let to_kin x = x
> end

I think that can be cut down to:

module M = struct
  type momentum = private kinematic
  let of_kin = %identity
  let to_kin = %identity
end

> Yes, it's a lot of boilerplate for each type, but you only have to
> write it once (per type), and cross-module inlining should give zero
> runtime cost.  If not, use "%identity", and expose it in the
> interface.  This method is along the lines of Anthony's proposal #4.
>
> E.

MfG
        Goswin


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

* Re: [Caml-list] Re: Subtyping structurally-equivalent records, or  something like it?
  2010-05-04 13:37       ` Edgar Friendly
  2010-05-05  9:33         ` Goswin von Brederlow
@ 2010-05-05 11:10         ` Yaron Minsky
  1 sibling, 0 replies; 13+ messages in thread
From: Yaron Minsky @ 2010-05-05 11:10 UTC (permalink / raw)
  To: Edgar Friendly; +Cc: caml-list

[-- Attachment #1: Type: text/plain, Size: 1052 bytes --]

On Tue, May 4, 2010 at 9:37 AM, Edgar Friendly <thelema314@gmail.com> wrote:

> module M : sig
>        type momentum
>        val of_kin : kinematic -> momentum
>        val to_kin : momentum -> kinematic
> end = struct
>        type momentum = kinematic
>        let of_kin x = x
>        let to_kin x = x
> end
>
> Yes, it's a lot of boilerplate for each type, but you only have to write it
> once (per type), and cross-module inlining should give zero runtime cost.
>  If not, use "%identity", and expose it in the interface.  This method is
> along the lines of Anthony's proposal #4.


You can do the above solution with essentially no boilerplate:

module M = struct
   type t = kinematic
   val to_kin x = x
   val of_kin x = x
end

module type S = sig
  type t
  val to_kin : t -> kinematic
  val of_kin : kinematic -> t
end

module Momentum : S = M
module Position : S = M
module Force : S = M

and so on.  Just  one line per kinematic-like type you want to create.

That said, I still think the phantom type solution will end up cleaner.

y

[-- Attachment #2: Type: text/html, Size: 1479 bytes --]

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

* Re: [Caml-list] Re: Subtyping structurally-equivalent records, or something like it?
  2010-05-05  9:31         ` Goswin von Brederlow
@ 2010-05-05 12:12           ` rossberg
  2010-05-05 16:46             ` Goswin von Brederlow
  0 siblings, 1 reply; 13+ messages in thread
From: rossberg @ 2010-05-05 12:12 UTC (permalink / raw)
  To: Goswin von Brederlow; +Cc: caml-list

"Goswin von Brederlow" <goswin-v-b@web.de>:
>
>>> This is not about optimized compiler in this case but about data
>>> representation. Even if you use an optimized compiler (which is not
>>> really the case with ocamlopt), you won't change datastructure
>>> representation to optimize.
>>
>> What do you mean? There is no reason in general why a compiler cannot
>> optimize data representations, and some do in cases like this.
>
> How could it? At least for any type that is public in a module.
>
> The data representation is part of the ABI. As such it is fixed and can
> in no way be optimized by the compiler. Only thing you can do is change
> the ABI and define a more optimized representation in the first place.

Yes, and I didn't say that OCaml easily could, given external constraints
like the one you mention. I only was objecting to the statement that this is
not an optimization.

> A better representation would be to combine the two:
>
> bar {
>   tag = 0 (for Bar)
>   size = 2
>   field[0] = int(x)
>   field[1] = int(y)
> }

That is called flattening or unboxing, and in degenerate use cases it can
actually be costly because you have to copy the record if you extract it
first-class. However, for the original case there would be a much simpler
optimization: if a data type has only one constructor (more precisely, one
except for nullary ones), you don't need to represent its tag at all, so the
whole indirection is unnecessary.

/Andreas


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

* Re: [Caml-list] Re: Subtyping structurally-equivalent records, or something like it?
  2010-05-05 12:12           ` rossberg
@ 2010-05-05 16:46             ` Goswin von Brederlow
  0 siblings, 0 replies; 13+ messages in thread
From: Goswin von Brederlow @ 2010-05-05 16:46 UTC (permalink / raw)
  To: rossberg; +Cc: Goswin von Brederlow, caml-list

rossberg@mpi-sws.org writes:

> "Goswin von Brederlow" <goswin-v-b@web.de>:
>>
>>>> This is not about optimized compiler in this case but about data
>>>> representation. Even if you use an optimized compiler (which is not
>>>> really the case with ocamlopt), you won't change datastructure
>>>> representation to optimize.
>>>
>>> What do you mean? There is no reason in general why a compiler cannot
>>> optimize data representations, and some do in cases like this.
>>
>> How could it? At least for any type that is public in a module.
>>
>> The data representation is part of the ABI. As such it is fixed and can
>> in no way be optimized by the compiler. Only thing you can do is change
>> the ABI and define a more optimized representation in the first place.
>
> Yes, and I didn't say that OCaml easily could, given external constraints
> like the one you mention. I only was objecting to the statement that this is
> not an optimization.
>
>> A better representation would be to combine the two:
>>
>> bar {
>>   tag = 0 (for Bar)
>>   size = 2
>>   field[0] = int(x)
>>   field[1] = int(y)
>> }
>
> That is called flattening or unboxing, and in degenerate use cases it can
> actually be costly because you have to copy the record if you extract it
> first-class. However, for the original case there would be a much simpler
> optimization: if a data type has only one constructor (more precisely, one
> except for nullary ones), you don't need to represent its tag at all, so the
> whole indirection is unnecessary.
>
> /Andreas

Actualy in this case you don't. In foo the "tag" part of the block is
unused and in bar it is the constructor id. (foo) and (Bar foo) just
happen to have the same representation. Extracting a foo from a bar
means you just ignore the tag part, which is already ignored anyway.

The case of only having one constructor can be seen as special case for
this in the case of records. But type gnarf = Gnarf of int could be
represented as plain int as you say. The idea is the same.


The reason ocaml does not do this is that defining lots of exception for
the representation of data makes the compiler much more complicated and
ocamls compiler aims at being simple. At least that's what has been said
in the past.

MfG
        Goswin


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

end of thread, other threads:[~2010-05-05 16:46 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-05-01 19:55 [Caml-list] Subtyping structurally-equivalent records, or something like it? Dario Teixeira
2010-05-01 20:01 ` Sylvain Le Gall
2010-05-04 10:33   ` [Caml-list] " AUGER Cédric
     [not found]   ` <4429.86797211251$1272970133@news.gmane.org>
2010-05-04 11:53     ` Sylvain Le Gall
2010-05-04 12:47       ` [Caml-list] " rossberg
2010-05-04 13:42         ` Sylvain Le Gall
2010-05-04 15:18           ` [Caml-list] " Fabrice Le Fessant
2010-05-05  9:31         ` Goswin von Brederlow
2010-05-05 12:12           ` rossberg
2010-05-05 16:46             ` Goswin von Brederlow
2010-05-04 13:37       ` Edgar Friendly
2010-05-05  9:33         ` Goswin von Brederlow
2010-05-05 11:10         ` Yaron Minsky

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