caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list]  How much optimized is the 'a option type ?
@ 2014-01-17  7:35 Damien Guichard
  2014-01-17  7:55 ` David House
  2014-01-17 14:36 ` Markus Mottl
  0 siblings, 2 replies; 53+ messages in thread
From: Damien Guichard @ 2014-01-17  7:35 UTC (permalink / raw)
  To: Caml Mailing List

Hello,

Compared to the code :

type 'a option = None | Some of 'a

How do an 'a option value performs ?
Any allocation saved ?
Any indirection removed ?

Is 'a option just like any sum type ?
Or is 'a option more like an ANSI C pointer type ?

Regards,

Damien Guichard



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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17  7:35 [Caml-list] How much optimized is the 'a option type ? Damien Guichard
@ 2014-01-17  7:55 ` David House
  2014-01-17  8:16   ` Julien Blond
  2014-01-17 14:36 ` Markus Mottl
  1 sibling, 1 reply; 53+ messages in thread
From: David House @ 2014-01-17  7:55 UTC (permalink / raw)
  To: Damien Guichard; +Cc: Caml Mailing List

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

It behaves identically to that type.

It is just like any other sum type. However, due to the way that sum types
are represented in memory, it is not that inefficient. The only thing that
makes it less efficient than a C pointer is the header block (necessary for
the GC). An option value always takes two words: one for the header, and
then either a pointer or a word that means "None".


On 17 January 2014 07:35, Damien Guichard <alphablock@orange.fr> wrote:

> Hello,
>
> Compared to the code :
>
> type 'a option = None | Some of 'a
>
> How do an 'a option value performs ?
> Any allocation saved ?
> Any indirection removed ?
>
> Is 'a option just like any sum type ?
> Or is 'a option more like an ANSI C pointer type ?
>
> Regards,
>
> Damien Guichard
>
>
>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>

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

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17  7:55 ` David House
@ 2014-01-17  8:16   ` Julien Blond
  2014-01-17  8:40     ` David House
  0 siblings, 1 reply; 53+ messages in thread
From: Julien Blond @ 2014-01-17  8:16 UTC (permalink / raw)
  To: David House; +Cc: Damien Guichard, Caml Mailing List

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

> An option value always takes two words: one for the header, and then
either a pointer or a word that means "None".

No. From the reference manual § 19.3.4 :

type 'a option = None           (* Val_int(0), i.e. just an integer value =
1 word *)
                     | Some of 'a   (* block of size 1 = [(header = 1 word)
+ (1 field = 1 word)] = 2 words *)


2014/1/17 David House <dhouse@janestreet.com>

> It behaves identically to that type.
>
> It is just like any other sum type. However, due to the way that sum types
> are represented in memory, it is not that inefficient. The only thing that
> makes it less efficient than a C pointer is the header block (necessary for
> the GC). An option value always takes two words: one for the header, and
> then either a pointer or a word that means "None".
>
>
> On 17 January 2014 07:35, Damien Guichard <alphablock@orange.fr> wrote:
>
>> Hello,
>>
>> Compared to the code :
>>
>> type 'a option = None | Some of 'a
>>
>> How do an 'a option value performs ?
>> Any allocation saved ?
>> Any indirection removed ?
>>
>> Is 'a option just like any sum type ?
>> Or is 'a option more like an ANSI C pointer type ?
>>
>> Regards,
>>
>> Damien Guichard
>>
>>
>>
>> --
>> Caml-list mailing list.  Subscription management and archives:
>> https://sympa.inria.fr/sympa/arc/caml-list
>> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
>> Bug reports: http://caml.inria.fr/bin/caml-bugs
>>
>
>

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

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17  8:16   ` Julien Blond
@ 2014-01-17  8:40     ` David House
  2014-01-17  9:10       ` Gabriel Scherer
       [not found]       ` <CAK=fH+jfi=GsMYBZzmuo=V5UAWimyxiiamY2+DkLg6F0i8XHGw@mail.gmail.com>
  0 siblings, 2 replies; 53+ messages in thread
From: David House @ 2014-01-17  8:40 UTC (permalink / raw)
  To: Julien Blond; +Cc: Damien Guichard, Caml Mailing List

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

Err, right, sorry. If you have None in, say, a record, that's not allocated
at all. Rather than there being a pointer in that field, there is special
word in that field which represents None.

If that field is a Some, then it's a pointer to a two word allocated block
which in turn points at the actual thing. So compared to a C pointer, there
an extra two words and one more indirection.


On 17 January 2014 08:16, Julien Blond <julien.blond@gmail.com> wrote:

> > An option value always takes two words: one for the header, and then
> either a pointer or a word that means "None".
>
> No. From the reference manual § 19.3.4 :
>
> type 'a option = None           (* Val_int(0), i.e. just an integer value
> = 1 word *)
>                      | Some of 'a   (* block of size 1 = [(header = 1
> word) + (1 field = 1 word)] = 2 words *)
>
>
> 2014/1/17 David House <dhouse@janestreet.com>
>
>> It behaves identically to that type.
>>
>> It is just like any other sum type. However, due to the way that sum
>> types are represented in memory, it is not that inefficient. The only thing
>> that makes it less efficient than a C pointer is the header block
>> (necessary for the GC). An option value always takes two words: one for the
>> header, and then either a pointer or a word that means "None".
>>
>>
>> On 17 January 2014 07:35, Damien Guichard <alphablock@orange.fr> wrote:
>>
>>> Hello,
>>>
>>> Compared to the code :
>>>
>>> type 'a option = None | Some of 'a
>>>
>>> How do an 'a option value performs ?
>>> Any allocation saved ?
>>> Any indirection removed ?
>>>
>>> Is 'a option just like any sum type ?
>>> Or is 'a option more like an ANSI C pointer type ?
>>>
>>> Regards,
>>>
>>> Damien Guichard
>>>
>>>
>>>
>>> --
>>> Caml-list mailing list.  Subscription management and archives:
>>> https://sympa.inria.fr/sympa/arc/caml-list
>>> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
>>> Bug reports: http://caml.inria.fr/bin/caml-bugs
>>>
>>
>>
>

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

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17  8:40     ` David House
@ 2014-01-17  9:10       ` Gabriel Scherer
  2014-01-17  9:22         ` Simon Cruanes
                           ` (2 more replies)
       [not found]       ` <CAK=fH+jfi=GsMYBZzmuo=V5UAWimyxiiamY2+DkLg6F0i8XHGw@mail.gmail.com>
  1 sibling, 3 replies; 53+ messages in thread
From: Gabriel Scherer @ 2014-01-17  9:10 UTC (permalink / raw)
  To: David House; +Cc: Julien Blond, Damien Guichard, Caml Mailing List

There have been recurrent discussions of optimizing `'a option` to
avoid allocation in some cases, which is interesting when it is used
as a default value for example. (The nice recent blog post by Thomas
Leonard also seems to assume that `'a option` is somehow optimized.)

My strictly personal opinion is that I doubt this would be a good
idea, because I expect a fair share of the programming practice that
currently use ('a option) to move to something like (('a,
error-description) either) later in their lifetime, and I wouldn't
want people to avoid to do that for performance concerns.
Historically, we've rather come to see special-case representation
optimizations (eg. array of floats) as a mistake -- but on the other
hand there is not much downside to record of floats.

The OCaml GC is very good at optimizing *short-lived* allocations, so
many idiomatic uses of option are in fact already quite fast despite
the allocation. Using an `'a option array` for values that start
undefined is not one of such cases. Hopefully in fifteen years we'll
be using programming languages with well-typed strong update such as
Mezzo ( http://protz.github.io/mezzo/ ), that can solve this problem
without any kind of ad-hoc optimization.

On Fri, Jan 17, 2014 at 9:40 AM, David House <dhouse@janestreet.com> wrote:
> Err, right, sorry. If you have None in, say, a record, that's not allocated
> at all. Rather than there being a pointer in that field, there is special
> word in that field which represents None.
>
> If that field is a Some, then it's a pointer to a two word allocated block
> which in turn points at the actual thing. So compared to a C pointer, there
> an extra two words and one more indirection.
>
>
> On 17 January 2014 08:16, Julien Blond <julien.blond@gmail.com> wrote:
>>
>> > An option value always takes two words: one for the header, and then
>> > either a pointer or a word that means "None".
>>
>> No. From the reference manual § 19.3.4 :
>>
>> type 'a option = None           (* Val_int(0), i.e. just an integer value
>> = 1 word *)
>>                      | Some of 'a   (* block of size 1 = [(header = 1
>> word) + (1 field = 1 word)] = 2 words *)
>>
>>
>> 2014/1/17 David House <dhouse@janestreet.com>
>>>
>>> It behaves identically to that type.
>>>
>>> It is just like any other sum type. However, due to the way that sum
>>> types are represented in memory, it is not that inefficient. The only thing
>>> that makes it less efficient than a C pointer is the header block (necessary
>>> for the GC). An option value always takes two words: one for the header, and
>>> then either a pointer or a word that means "None".
>>>
>>>
>>> On 17 January 2014 07:35, Damien Guichard <alphablock@orange.fr> wrote:
>>>>
>>>> Hello,
>>>>
>>>> Compared to the code :
>>>>
>>>> type 'a option = None | Some of 'a
>>>>
>>>> How do an 'a option value performs ?
>>>> Any allocation saved ?
>>>> Any indirection removed ?
>>>>
>>>> Is 'a option just like any sum type ?
>>>> Or is 'a option more like an ANSI C pointer type ?
>>>>
>>>> Regards,
>>>>
>>>> Damien Guichard
>>>>
>>>>
>>>>
>>>> --
>>>> Caml-list mailing list.  Subscription management and archives:
>>>> https://sympa.inria.fr/sympa/arc/caml-list
>>>> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
>>>> Bug reports: http://caml.inria.fr/bin/caml-bugs
>>>
>>>
>>
>

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

* Re: [Caml-list] How much optimized is the 'a option type ?
       [not found]       ` <CAK=fH+jfi=GsMYBZzmuo=V5UAWimyxiiamY2+DkLg6F0i8XHGw@mail.gmail.com>
@ 2014-01-17  9:11         ` David House
  2014-01-17 11:23           ` Jonathan Kimmitt
  0 siblings, 1 reply; 53+ messages in thread
From: David House @ 2014-01-17  9:11 UTC (permalink / raw)
  To: Julien Blond; +Cc: Damien Guichard, Caml Mailing List

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

My attachment got rejected by the list. http://imgur.com/de9SBnA


On 17 January 2014 09:09, David House <dhouse@janestreet.com> wrote:

> Here's some high-tech computer visualisation to illustrate this.
>
>
> On 17 January 2014 08:40, David House <dhouse@janestreet.com> wrote:
>
>> Err, right, sorry. If you have None in, say, a record, that's not
>> allocated at all. Rather than there being a pointer in that field, there is
>> special word in that field which represents None.
>>
>> If that field is a Some, then it's a pointer to a two word allocated
>> block which in turn points at the actual thing. So compared to a C pointer,
>> there an extra two words and one more indirection.
>>
>>
>> On 17 January 2014 08:16, Julien Blond <julien.blond@gmail.com> wrote:
>>
>>> > An option value always takes two words: one for the header, and then
>>> either a pointer or a word that means "None".
>>>
>>> No. From the reference manual § 19.3.4 :
>>>
>>> type 'a option = None           (* Val_int(0), i.e. just an integer
>>> value = 1 word *)
>>>                      | Some of 'a   (* block of size 1 = [(header = 1
>>> word) + (1 field = 1 word)] = 2 words *)
>>>
>>>
>>> 2014/1/17 David House <dhouse@janestreet.com>
>>>
>>>> It behaves identically to that type.
>>>>
>>>> It is just like any other sum type. However, due to the way that sum
>>>> types are represented in memory, it is not that inefficient. The only thing
>>>> that makes it less efficient than a C pointer is the header block
>>>> (necessary for the GC). An option value always takes two words: one for the
>>>> header, and then either a pointer or a word that means "None".
>>>>
>>>>
>>>> On 17 January 2014 07:35, Damien Guichard <alphablock@orange.fr> wrote:
>>>>
>>>>> Hello,
>>>>>
>>>>> Compared to the code :
>>>>>
>>>>> type 'a option = None | Some of 'a
>>>>>
>>>>> How do an 'a option value performs ?
>>>>> Any allocation saved ?
>>>>> Any indirection removed ?
>>>>>
>>>>> Is 'a option just like any sum type ?
>>>>> Or is 'a option more like an ANSI C pointer type ?
>>>>>
>>>>> Regards,
>>>>>
>>>>> Damien Guichard
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Caml-list mailing list.  Subscription management and archives:
>>>>> https://sympa.inria.fr/sympa/arc/caml-list
>>>>> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
>>>>> Bug reports: http://caml.inria.fr/bin/caml-bugs
>>>>>
>>>>
>>>>
>>>
>>
>

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

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17  9:10       ` Gabriel Scherer
@ 2014-01-17  9:22         ` Simon Cruanes
  2014-01-17 17:57           ` Gerd Stolpmann
  2014-01-18  1:01         ` Jon Harrop
  2014-01-24 10:06         ` Alain Frisch
  2 siblings, 1 reply; 53+ messages in thread
From: Simon Cruanes @ 2014-01-17  9:22 UTC (permalink / raw)
  To: Gabriel Scherer
  Cc: David House, Julien Blond, Damien Guichard, Caml Mailing List

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

Le Fri, 17 Jan 2014, Gabriel Scherer a écrit :

> There have been recurrent discussions of optimizing `'a option` to
> avoid allocation in some cases, which is interesting when it is used
> as a default value for example. (The nice recent blog post by Thomas
> Leonard also seems to assume that `'a option` is somehow optimized.)
> 
> My strictly personal opinion is that I doubt this would be a good
> idea, because I expect a fair share of the programming practice that
> currently use ('a option) to move to something like (('a,
> error-description) either) later in their lifetime, and I wouldn't
> want people to avoid to do that for performance concerns.
> Historically, we've rather come to see special-case representation
> optimizations (eg. array of floats) as a mistake -- but on the other
> hand there is not much downside to record of floats.

I think optimization of some local uses of options, such as:

let rec iter_stream f s =
    match (try Some (MyStream.get s) with End_of_stream -> None) with
    | None -> ()
    | Some (x, s') ->
        f x;
        iter_stream f s'

where an option is used to keep the function tail-rec (I've heard
several people tell me they often need to use this), or other cases like
optional parameters (which are not going to move to Either), would be
useful and future-proof. I hope the current work on optimizations will
help with this kind of cases (removing useless allocations of local
options, references, exceptions when no escape is possible).

</wishlist>
</2cents>
</</>>

-- 
Simon

[-- Attachment #2: Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17  9:11         ` David House
@ 2014-01-17 11:23           ` Jonathan Kimmitt
  2014-01-17 13:46             ` Nicolas Braud-Santoni
                               ` (2 more replies)
  0 siblings, 3 replies; 53+ messages in thread
From: Jonathan Kimmitt @ 2014-01-17 11:23 UTC (permalink / raw)
  To: caml-list

In my humble opinion the main purpose of Some _ | None is to avoid the
requirement for a nil pointer in OCaml. If an external function wants to
return nil in order to indicate, for example that a certain resource is not
available, it can return None instead and this prevents dereferencing a nil
pointer in OCaml because the None cannot be dereferenced. If you compare this
behaviour with the inferior clone F# written by Microsoft, you can see that
one of the things they added to the language was a nil pointer, thus
abandoning all type safety immediately and all because they did not want to
change their .NET runtime system for C# etc. They also have the notion of
initialising a typed object to in an invalid default, which is another obvious
disaster area. Oh and did I mention operators like +/- etc are overloaded so
you cannot infer function types without adding type annotations.
The final insult is to make indentation significant in the syntax so that if
you post a program to a list which does not respect whitespace (for example
using a well-known Microsoft mail client), it completely destroys the meaning
of the program.

I'm sure the authors of F# have their reasons for making all these changes,
and I'm not one to stand in the way of progress, and I don't set out to offend
anybody, but I think they got it wrong ...

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17 11:23           ` Jonathan Kimmitt
@ 2014-01-17 13:46             ` Nicolas Braud-Santoni
  2014-01-17 13:56               ` Frédéric Bour
  2014-01-17 14:02               ` Yaron Minsky
  2014-01-18  1:18             ` Jon Harrop
  2014-01-20 10:16             ` Goswin von Brederlow
  2 siblings, 2 replies; 53+ messages in thread
From: Nicolas Braud-Santoni @ 2014-01-17 13:46 UTC (permalink / raw)
  To: caml-list

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

On 17/01/2014 12:23, Jonathan Kimmitt wrote:
> In my humble opinion the main purpose of Some _ | None is to avoid the
> requirement for a nil pointer in OCaml. If an external function wants to
> return nil in order to indicate, for example that a certain resource is not
> available, it can return None instead and this prevents dereferencing a nil
> pointer in OCaml because the None cannot be dereferenced.
Yes.
This doesn't forbid the compiler from representing 'a option values as
pointers.
Indeed, the type system already enforces that the None case is handled
and the representation of None and Some _ do not matter.

That said, I agree with Gabriel Scherer : adding optimizations specific
to 'a option might refrain people wanting to switch to more appropriate
datatypes.
However, would is be possible to “optimize away” all types of the form
“type 'a t = X of 'a | A | B | ...” (with at most one non-constant
constructor) ?
Would it be worth doing ?


Kind regards,
Nicolas


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17 13:46             ` Nicolas Braud-Santoni
@ 2014-01-17 13:56               ` Frédéric Bour
  2014-01-17 14:02               ` Yaron Minsky
  1 sibling, 0 replies; 53+ messages in thread
From: Frédéric Bour @ 2014-01-17 13:56 UTC (permalink / raw)
  To: Nicolas Braud-Santoni, caml-list


Le 17/01/2014 14:46, Nicolas Braud-Santoni a écrit :
> On 17/01/2014 12:23, Jonathan Kimmitt wrote:
>> In my humble opinion the main purpose of Some _ | None is to avoid the
>> requirement for a nil pointer in OCaml. If an external function wants to
>> return nil in order to indicate, for example that a certain resource is not
>> available, it can return None instead and this prevents dereferencing a nil
>> pointer in OCaml because the None cannot be dereferenced.
> Yes.
> This doesn't forbid the compiler from representing 'a option values as
> pointers.
> Indeed, the type system already enforces that the None case is handled
> and the representation of None and Some _ do not matter.
>
> That said, I agree with Gabriel Scherer : adding optimizations specific
> to 'a option might refrain people wanting to switch to more appropriate
> datatypes.
> However, would is be possible to “optimize away” all types of the form
> “type 'a t = X of 'a | A | B | ...” (with at most one non-constant
> constructor) ?
> Would it be worth doing ?

This won't work when used with 'a = another type with constant constructors.
And what about 'a 'a t?

Sticking to a uniform representation prevents a lot of problem.

> Kind regards,
> Nicolas


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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17 13:46             ` Nicolas Braud-Santoni
  2014-01-17 13:56               ` Frédéric Bour
@ 2014-01-17 14:02               ` Yaron Minsky
  2014-01-17 14:09                 ` Simon Cruanes
                                   ` (2 more replies)
  1 sibling, 3 replies; 53+ messages in thread
From: Yaron Minsky @ 2014-01-17 14:02 UTC (permalink / raw)
  To: Nicolas Braud-Santoni; +Cc: caml-list

I also agree with Gabriel that an option-specific optimization is not
clearly the right move.

But I wonder if a more general optimization that provided the
possibility of minting "fast-path" variants.  i.e., one could have an
annotation that marked a given branch of a variant as the
"no-indirection" one, i.e., the one that doesn't lead to the
allocation of an extra block:

type ('a,'b) result =
     | Ok of 'a [@@no_indirection]
     | Error of 'b

would lead to a type where [Ok x == x].  Some cleverness is required
then for the representation of the [Error] branch.  In particular,
you'd need some dynamic test you could run to see if you were using a
value that was not the fast-path one.

The thing that I don't know if there's a solution for is the nesting
problem.  i.e., can you effectively distinguish:

  Ok (Ok (Error x))

from

  Error x

since they would have the same physical representation.  I'm not sure
if some variant of the counting trick used for options would work here
or not.  But if you could get this, it would make it possible to avoid
a large number of dirty Obj.magic hacks that people need to do to
build efficient datastructures in practice.  The fact that the stdlib
needs to use Obj.magic to get the necessary performance is, I think, a
sign that something important is missing from the language.  I'm not
sure if this is quite it, to be clear.

y


On Fri, Jan 17, 2014 at 8:46 AM, Nicolas Braud-Santoni
<nicolas.braudsantoni@gmail.com> wrote:
> On 17/01/2014 12:23, Jonathan Kimmitt wrote:
>> In my humble opinion the main purpose of Some _ | None is to avoid the
>> requirement for a nil pointer in OCaml. If an external function wants to
>> return nil in order to indicate, for example that a certain resource is not
>> available, it can return None instead and this prevents dereferencing a nil
>> pointer in OCaml because the None cannot be dereferenced.
> Yes.
> This doesn't forbid the compiler from representing 'a option values as
> pointers.
> Indeed, the type system already enforces that the None case is handled
> and the representation of None and Some _ do not matter.
>
> That said, I agree with Gabriel Scherer : adding optimizations specific
> to 'a option might refrain people wanting to switch to more appropriate
> datatypes.
> However, would is be possible to “optimize away” all types of the form
> “type 'a t = X of 'a | A | B | ...” (with at most one non-constant
> constructor) ?
> Would it be worth doing ?
>
>
> Kind regards,
> Nicolas
>

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17 14:02               ` Yaron Minsky
@ 2014-01-17 14:09                 ` Simon Cruanes
  2014-01-17 22:52                   ` Yaron Minsky
  2014-01-18  1:37                   ` Jon Harrop
  2014-01-17 14:24                 ` Gabriel Scherer
  2014-01-18  1:27                 ` Jon Harrop
  2 siblings, 2 replies; 53+ messages in thread
From: Simon Cruanes @ 2014-01-17 14:09 UTC (permalink / raw)
  To: Yaron Minsky; +Cc: Nicolas Braud-Santoni, caml-list

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

Le Fri, 17 Jan 2014, Yaron Minsky a écrit :
> I also agree with Gabriel that an option-specific optimization is not
> clearly the right move.
> 
> But I wonder if a more general optimization that provided the
> possibility of minting "fast-path" variants.  i.e., one could have an
> annotation that marked a given branch of a variant as the
> "no-indirection" one, i.e., the one that doesn't lead to the
> allocation of an extra block:
> 
> type ('a,'b) result =
>      | Ok of 'a [@@no_indirection]
>      | Error of 'b
> 
> would lead to a type where [Ok x == x].  Some cleverness is required
> then for the representation of the [Error] branch.  In particular,
> you'd need some dynamic test you could run to see if you were using a
> value that was not the fast-path one.
> 
> The thing that I don't know if there's a solution for is the nesting
> problem.  i.e., can you effectively distinguish:
> 
>   Ok (Ok (Error x))
> 
> from
> 
>   Error x
> 
> since they would have the same physical representation.  I'm not sure
> if some variant of the counting trick used for options would work here
> or not.  But if you could get this, it would make it possible to avoid
> a large number of dirty Obj.magic hacks that people need to do to
> build efficient datastructures in practice.  The fact that the stdlib
> needs to use Obj.magic to get the necessary performance is, I think, a
> sign that something important is missing from the language.  I'm not
> sure if this is quite it, to be clear.

Maybe I'm stating the obvious, but wouldn't value types be the general
solution here? Assuming the optimizer can guarantee that the option
value will not outlive the current scope, the value can be allocated on
the stack or in registers. That's probably fast enough for most uses,
isn't it? I think rust deals with option values exactly this way.


-- 
Simon

[-- Attachment #2: Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17 14:02               ` Yaron Minsky
  2014-01-17 14:09                 ` Simon Cruanes
@ 2014-01-17 14:24                 ` Gabriel Scherer
  2014-01-17 22:29                   ` Yaron Minsky
  2014-01-18  1:27                 ` Jon Harrop
  2 siblings, 1 reply; 53+ messages in thread
From: Gabriel Scherer @ 2014-01-17 14:24 UTC (permalink / raw)
  To: Yaron Minsky; +Cc: Nicolas Braud-Santoni, caml-list

> The fact that the stdlib
> needs to use Obj.magic to get the necessary performance is, I think, a
> sign that something important is missing from the language.

I think this specific example needs to die. Yes, there is an Obj.magic
in the implementation of Queue, and this mistake was committed more
than a decade ago. But we could perfectly remove this use of Obj.magic
and use different implementation techniques to get equally efficient
(or better) code. But there is no reason to change code that works
well enough.

That some Obj.magic remains in some old code is *no excuse* to use it
today or tomorrow.

On Fri, Jan 17, 2014 at 3:02 PM, Yaron Minsky <yminsky@janestreet.com> wrote:
> I also agree with Gabriel that an option-specific optimization is not
> clearly the right move.
>
> But I wonder if a more general optimization that provided the
> possibility of minting "fast-path" variants.  i.e., one could have an
> annotation that marked a given branch of a variant as the
> "no-indirection" one, i.e., the one that doesn't lead to the
> allocation of an extra block:
>
> type ('a,'b) result =
>      | Ok of 'a [@@no_indirection]
>      | Error of 'b
>
> would lead to a type where [Ok x == x].  Some cleverness is required
> then for the representation of the [Error] branch.  In particular,
> you'd need some dynamic test you could run to see if you were using a
> value that was not the fast-path one.
>
> The thing that I don't know if there's a solution for is the nesting
> problem.  i.e., can you effectively distinguish:
>
>   Ok (Ok (Error x))
>
> from
>
>   Error x
>
> since they would have the same physical representation.  I'm not sure
> if some variant of the counting trick used for options would work here
> or not.  But if you could get this, it would make it possible to avoid
> a large number of dirty Obj.magic hacks that people need to do to
> build efficient datastructures in practice.  The fact that the stdlib
> needs to use Obj.magic to get the necessary performance is, I think, a
> sign that something important is missing from the language.  I'm not
> sure if this is quite it, to be clear.
>
> y
>
>
> On Fri, Jan 17, 2014 at 8:46 AM, Nicolas Braud-Santoni
> <nicolas.braudsantoni@gmail.com> wrote:
>> On 17/01/2014 12:23, Jonathan Kimmitt wrote:
>>> In my humble opinion the main purpose of Some _ | None is to avoid the
>>> requirement for a nil pointer in OCaml. If an external function wants to
>>> return nil in order to indicate, for example that a certain resource is not
>>> available, it can return None instead and this prevents dereferencing a nil
>>> pointer in OCaml because the None cannot be dereferenced.
>> Yes.
>> This doesn't forbid the compiler from representing 'a option values as
>> pointers.
>> Indeed, the type system already enforces that the None case is handled
>> and the representation of None and Some _ do not matter.
>>
>> That said, I agree with Gabriel Scherer : adding optimizations specific
>> to 'a option might refrain people wanting to switch to more appropriate
>> datatypes.
>> However, would is be possible to “optimize away” all types of the form
>> “type 'a t = X of 'a | A | B | ...” (with at most one non-constant
>> constructor) ?
>> Would it be worth doing ?
>>
>>
>> Kind regards,
>> Nicolas
>>
>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17  7:35 [Caml-list] How much optimized is the 'a option type ? Damien Guichard
  2014-01-17  7:55 ` David House
@ 2014-01-17 14:36 ` Markus Mottl
  2014-01-17 15:49   ` Yotam Barnoy
  2014-01-20 10:09   ` Goswin von Brederlow
  1 sibling, 2 replies; 53+ messages in thread
From: Markus Mottl @ 2014-01-17 14:36 UTC (permalink / raw)
  To: Damien Guichard; +Cc: Caml Mailing List

Others have already answered about memory representation, but there is
one thing about allocations that many OCaml programmers may not yet be
aware of and that can make a noticeable performance difference when
used wisely: the OCaml compiler will inspect your code and, under the
right conditions, batch together allocations.  E.g. consider this
function (references are records, btw.):

  let f n =
    let x = ref (ref (Some (Some n))) in
    [(x, n); (x, n)]

One might naively assume that this would lead to seven or so
allocations.  But if you inspect the assembly, you'll see only one
allocation followed by mere initialization assignments.

Such allocation batches can break if, for example, the code calls
non-inlined (e.g. recursive or external) functions.  I'm not quite
sure about all the rules there, but it's generally trivial to just
look at the assembler output to find out what the compiler is doing.
In some cases merely calling all functions before any allocations take
place can speed up your code.  There are even cases where it may be
more efficient to allocate several values in one chunk though only
some may be needed depending on branches taken later.

Regards,
Markus

On Fri, Jan 17, 2014 at 2:35 AM, Damien Guichard <alphablock@orange.fr> wrote:
> Hello,
>
> Compared to the code :
>
> type 'a option = None | Some of 'a
>
> How do an 'a option value performs ?
> Any allocation saved ?
> Any indirection removed ?
>
> Is 'a option just like any sum type ?
> Or is 'a option more like an ANSI C pointer type ?
>
> Regards,
>
> Damien Guichard
>
>
>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs



-- 
Markus Mottl        http://www.ocaml.info        markus.mottl@gmail.com

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17 14:36 ` Markus Mottl
@ 2014-01-17 15:49   ` Yotam Barnoy
  2014-01-17 16:22     ` Markus Mottl
  2014-01-20 10:09   ` Goswin von Brederlow
  1 sibling, 1 reply; 53+ messages in thread
From: Yotam Barnoy @ 2014-01-17 15:49 UTC (permalink / raw)
  To: Markus Mottl; +Cc: Damien Guichard, Caml Mailing List

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

That reminds me -- what is the situation regarding inlining? Is there work
being done on inlining from other modules? Is heavy inlining being done
within a module? Would it be possible to annotate with [@@inline] to give
hints to the compiler at some point?

-Yotam


On Fri, Jan 17, 2014 at 9:36 AM, Markus Mottl <markus.mottl@gmail.com>wrote:

> Others have already answered about memory representation, but there is
> one thing about allocations that many OCaml programmers may not yet be
> aware of and that can make a noticeable performance difference when
> used wisely: the OCaml compiler will inspect your code and, under the
> right conditions, batch together allocations.  E.g. consider this
> function (references are records, btw.):
>
>   let f n =
>     let x = ref (ref (Some (Some n))) in
>     [(x, n); (x, n)]
>
> One might naively assume that this would lead to seven or so
> allocations.  But if you inspect the assembly, you'll see only one
> allocation followed by mere initialization assignments.
>
> Such allocation batches can break if, for example, the code calls
> non-inlined (e.g. recursive or external) functions.  I'm not quite
> sure about all the rules there, but it's generally trivial to just
> look at the assembler output to find out what the compiler is doing.
> In some cases merely calling all functions before any allocations take
> place can speed up your code.  There are even cases where it may be
> more efficient to allocate several values in one chunk though only
> some may be needed depending on branches taken later.
>
> Regards,
> Markus
>
> On Fri, Jan 17, 2014 at 2:35 AM, Damien Guichard <alphablock@orange.fr>
> wrote:
> > Hello,
> >
> > Compared to the code :
> >
> > type 'a option = None | Some of 'a
> >
> > How do an 'a option value performs ?
> > Any allocation saved ?
> > Any indirection removed ?
> >
> > Is 'a option just like any sum type ?
> > Or is 'a option more like an ANSI C pointer type ?
> >
> > Regards,
> >
> > Damien Guichard
> >
> >
> >
> > --
> > Caml-list mailing list.  Subscription management and archives:
> > https://sympa.inria.fr/sympa/arc/caml-list
> > Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> > Bug reports: http://caml.inria.fr/bin/caml-bugs
>
>
>
> --
> Markus Mottl        http://www.ocaml.info        markus.mottl@gmail.com
>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>

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

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17 15:49   ` Yotam Barnoy
@ 2014-01-17 16:22     ` Markus Mottl
  0 siblings, 0 replies; 53+ messages in thread
From: Markus Mottl @ 2014-01-17 16:22 UTC (permalink / raw)
  To: Yotam Barnoy; +Cc: Damien Guichard, Caml Mailing List

Cross-module inlining (even across compilation units) is already
supported.  I guess what you mean is whether functor arguments are
inlined, which is not yet the case.  There has been some recent work
on this:

  http://www.ocamlpro.com/blog/2013/07/11/inlining-progress-report.html

I'd really love to see something like that in the compiler.

Regards,
Markus

On Fri, Jan 17, 2014 at 10:49 AM, Yotam Barnoy <yotambarnoy@gmail.com> wrote:
> That reminds me -- what is the situation regarding inlining? Is there work
> being done on inlining from other modules? Is heavy inlining being done
> within a module? Would it be possible to annotate with [@@inline] to give
> hints to the compiler at some point?
>
> -Yotam
>
>
> On Fri, Jan 17, 2014 at 9:36 AM, Markus Mottl <markus.mottl@gmail.com>
> wrote:
>>
>> Others have already answered about memory representation, but there is
>> one thing about allocations that many OCaml programmers may not yet be
>> aware of and that can make a noticeable performance difference when
>> used wisely: the OCaml compiler will inspect your code and, under the
>> right conditions, batch together allocations.  E.g. consider this
>> function (references are records, btw.):
>>
>>   let f n =
>>     let x = ref (ref (Some (Some n))) in
>>     [(x, n); (x, n)]
>>
>> One might naively assume that this would lead to seven or so
>> allocations.  But if you inspect the assembly, you'll see only one
>> allocation followed by mere initialization assignments.
>>
>> Such allocation batches can break if, for example, the code calls
>> non-inlined (e.g. recursive or external) functions.  I'm not quite
>> sure about all the rules there, but it's generally trivial to just
>> look at the assembler output to find out what the compiler is doing.
>> In some cases merely calling all functions before any allocations take
>> place can speed up your code.  There are even cases where it may be
>> more efficient to allocate several values in one chunk though only
>> some may be needed depending on branches taken later.
>>
>> Regards,
>> Markus
>>
>> On Fri, Jan 17, 2014 at 2:35 AM, Damien Guichard <alphablock@orange.fr>
>> wrote:
>> > Hello,
>> >
>> > Compared to the code :
>> >
>> > type 'a option = None | Some of 'a
>> >
>> > How do an 'a option value performs ?
>> > Any allocation saved ?
>> > Any indirection removed ?
>> >
>> > Is 'a option just like any sum type ?
>> > Or is 'a option more like an ANSI C pointer type ?
>> >
>> > Regards,
>> >
>> > Damien Guichard
>> >
>> >
>> >
>> > --
>> > Caml-list mailing list.  Subscription management and archives:
>> > https://sympa.inria.fr/sympa/arc/caml-list
>> > Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
>> > Bug reports: http://caml.inria.fr/bin/caml-bugs
>>
>>
>>
>> --
>> Markus Mottl        http://www.ocaml.info        markus.mottl@gmail.com
>>
>> --
>> Caml-list mailing list.  Subscription management and archives:
>> https://sympa.inria.fr/sympa/arc/caml-list
>> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
>> Bug reports: http://caml.inria.fr/bin/caml-bugs
>
>



-- 
Markus Mottl        http://www.ocaml.info        markus.mottl@gmail.com

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17  9:22         ` Simon Cruanes
@ 2014-01-17 17:57           ` Gerd Stolpmann
  2014-01-18  1:35             ` Jon Harrop
  0 siblings, 1 reply; 53+ messages in thread
From: Gerd Stolpmann @ 2014-01-17 17:57 UTC (permalink / raw)
  To: Simon Cruanes
  Cc: Gabriel Scherer, David House, Julien Blond, Damien Guichard,
	Caml Mailing List

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

Am Freitag, den 17.01.2014, 10:22 +0100 schrieb Simon Cruanes:
> Le Fri, 17 Jan 2014, Gabriel Scherer a écrit :
> 
> > There have been recurrent discussions of optimizing `'a option` to
> > avoid allocation in some cases, which is interesting when it is used
> > as a default value for example. (The nice recent blog post by Thomas
> > Leonard also seems to assume that `'a option` is somehow optimized.)
> > 
> > My strictly personal opinion is that I doubt this would be a good
> > idea, because I expect a fair share of the programming practice that
> > currently use ('a option) to move to something like (('a,
> > error-description) either) later in their lifetime, and I wouldn't
> > want people to avoid to do that for performance concerns.
> > Historically, we've rather come to see special-case representation
> > optimizations (eg. array of floats) as a mistake -- but on the other
> > hand there is not much downside to record of floats.
> 
> I think optimization of some local uses of options, such as:

I also think that local uses of options (and other variant types) could
be candidates for optimization. Gabriel is right that the GC is good at
short-living values, but that still leaves room for getting better with
ultra-short-living values.

My idea would be to try to delay the allocation of the block, and to use
two registers, i.e. one for the tag, and one for the tagged inner value.
First when the constructed value is passed to some other function, or
returned, or stored inside another block, or in another register, the
allocation is really done. Of course, this could also result in more
work in total (especially when the compiler has no idea what the desired
fast path of the algorithm is), and I guess the real problem is that you
need a good heuristics to decide when to do this. But there are at least
two criterions at hand:

 - You are not under pressure with registers
 - All consumers of the constructed value are inside the same function

I guess this would result in a quite heavy patch for the comparatively
small effect, and that's why it is not yet done.


Gerd


> let rec iter_stream f s =
>     match (try Some (MyStream.get s) with End_of_stream -> None) with
>     | None -> ()
>     | Some (x, s') ->
>         f x;
>         iter_stream f s'
> 
> where an option is used to keep the function tail-rec (I've heard
> several people tell me they often need to use this), or other cases like
> optional parameters (which are not going to move to Either), would be
> useful and future-proof. I hope the current work on optimizations will
> help with this kind of cases (removing useless allocations of local
> options, references, exceptions when no escape is possible).
> 
> </wishlist>
> </2cents>
> </</>>
> 

-- 
------------------------------------------------------------
Gerd Stolpmann, Darmstadt, Germany    gerd@gerd-stolpmann.de
My OCaml site:          http://www.camlcity.org
Contact details:        http://www.camlcity.org/contact.html
Company homepage:       http://www.gerd-stolpmann.de
------------------------------------------------------------


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17 14:24                 ` Gabriel Scherer
@ 2014-01-17 22:29                   ` Yaron Minsky
  0 siblings, 0 replies; 53+ messages in thread
From: Yaron Minsky @ 2014-01-17 22:29 UTC (permalink / raw)
  To: Gabriel Scherer; +Cc: Nicolas Braud-Santoni, caml-list

I agree that representation hacking (which is what Obj.magic is all
about) is something that should be done rarely, and I don't think the
Queue example justifies it.  There are other hacks, though, that make
sense, like the hack for lazy values, which I think is totally worth
it.

We've had to do a number of Obj.magic hacks in Core_kernel to get it
to perform adequately.  I think those hacks are a reasonably good
place to look for inspiration as to how to make OCaml more hospitable
for those with stringent performance requirements.

For what it's worth, GADTs have been a big win in this regard, by
making access to existentials cheap and easy, which can avoid a lot of
pointless allocation of closures in complex libraries.  I'd like to
see this improve yet further by allowing for existential values to be
created without an extra allocated block, which the GADT approach
currently requires.

If you're interested, you can look at Core_stack, Flat_queue, Dequeue
and Pool to see some examples where we've needed to use Obj.magic for
performance reasons.

y

On Fri, Jan 17, 2014 at 9:24 AM, Gabriel Scherer
<gabriel.scherer@gmail.com> wrote:
>> The fact that the stdlib
>> needs to use Obj.magic to get the necessary performance is, I think, a
>> sign that something important is missing from the language.
>
> I think this specific example needs to die. Yes, there is an Obj.magic
> in the implementation of Queue, and this mistake was committed more
> than a decade ago. But we could perfectly remove this use of Obj.magic
> and use different implementation techniques to get equally efficient
> (or better) code. But there is no reason to change code that works
> well enough.
>
> That some Obj.magic remains in some old code is *no excuse* to use it
> today or tomorrow.
>
> On Fri, Jan 17, 2014 at 3:02 PM, Yaron Minsky <yminsky@janestreet.com> wrote:
>> I also agree with Gabriel that an option-specific optimization is not
>> clearly the right move.
>>
>> But I wonder if a more general optimization that provided the
>> possibility of minting "fast-path" variants.  i.e., one could have an
>> annotation that marked a given branch of a variant as the
>> "no-indirection" one, i.e., the one that doesn't lead to the
>> allocation of an extra block:
>>
>> type ('a,'b) result =
>>      | Ok of 'a [@@no_indirection]
>>      | Error of 'b
>>
>> would lead to a type where [Ok x == x].  Some cleverness is required
>> then for the representation of the [Error] branch.  In particular,
>> you'd need some dynamic test you could run to see if you were using a
>> value that was not the fast-path one.
>>
>> The thing that I don't know if there's a solution for is the nesting
>> problem.  i.e., can you effectively distinguish:
>>
>>   Ok (Ok (Error x))
>>
>> from
>>
>>   Error x
>>
>> since they would have the same physical representation.  I'm not sure
>> if some variant of the counting trick used for options would work here
>> or not.  But if you could get this, it would make it possible to avoid
>> a large number of dirty Obj.magic hacks that people need to do to
>> build efficient datastructures in practice.  The fact that the stdlib
>> needs to use Obj.magic to get the necessary performance is, I think, a
>> sign that something important is missing from the language.  I'm not
>> sure if this is quite it, to be clear.
>>
>> y
>>
>>
>> On Fri, Jan 17, 2014 at 8:46 AM, Nicolas Braud-Santoni
>> <nicolas.braudsantoni@gmail.com> wrote:
>>> On 17/01/2014 12:23, Jonathan Kimmitt wrote:
>>>> In my humble opinion the main purpose of Some _ | None is to avoid the
>>>> requirement for a nil pointer in OCaml. If an external function wants to
>>>> return nil in order to indicate, for example that a certain resource is not
>>>> available, it can return None instead and this prevents dereferencing a nil
>>>> pointer in OCaml because the None cannot be dereferenced.
>>> Yes.
>>> This doesn't forbid the compiler from representing 'a option values as
>>> pointers.
>>> Indeed, the type system already enforces that the None case is handled
>>> and the representation of None and Some _ do not matter.
>>>
>>> That said, I agree with Gabriel Scherer : adding optimizations specific
>>> to 'a option might refrain people wanting to switch to more appropriate
>>> datatypes.
>>> However, would is be possible to “optimize away” all types of the form
>>> “type 'a t = X of 'a | A | B | ...” (with at most one non-constant
>>> constructor) ?
>>> Would it be worth doing ?
>>>
>>>
>>> Kind regards,
>>> Nicolas
>>>
>>
>> --
>> Caml-list mailing list.  Subscription management and archives:
>> https://sympa.inria.fr/sympa/arc/caml-list
>> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
>> Bug reports: http://caml.inria.fr/bin/caml-bugs

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17 14:09                 ` Simon Cruanes
@ 2014-01-17 22:52                   ` Yaron Minsky
  2014-01-18  1:37                   ` Jon Harrop
  1 sibling, 0 replies; 53+ messages in thread
From: Yaron Minsky @ 2014-01-17 22:52 UTC (permalink / raw)
  To: Simon Cruanes; +Cc: Nicolas Braud-Santoni, caml-list

I don't think it's enough.  Quite often these values are long-lived
enough that the analysis for short-lived objects would not help.
Short lived allocations are considerably cheaper anyway, so the bigger
win is on allocations that make it to the major heap.

Representation hacking has good uses.  Lazy is a fine example, where
lazy values are made considerably cheaper by the fact that OCaml
removes the extra level of indirection when a lazy is forced.

Not all representation hacks have worked out so well, I would argue.
I think there's relatively wide agreement that we'd be better off
without the float hack for arrays.  It complicates lots of things,
including the lazy hack!

y

On Fri, Jan 17, 2014 at 9:09 AM, Simon Cruanes
<simon.cruanes.2007@m4x.org> wrote:
> Le Fri, 17 Jan 2014, Yaron Minsky a écrit :
>> I also agree with Gabriel that an option-specific optimization is not
>> clearly the right move.
>>
>> But I wonder if a more general optimization that provided the
>> possibility of minting "fast-path" variants.  i.e., one could have an
>> annotation that marked a given branch of a variant as the
>> "no-indirection" one, i.e., the one that doesn't lead to the
>> allocation of an extra block:
>>
>> type ('a,'b) result =
>>      | Ok of 'a [@@no_indirection]
>>      | Error of 'b
>>
>> would lead to a type where [Ok x == x].  Some cleverness is required
>> then for the representation of the [Error] branch.  In particular,
>> you'd need some dynamic test you could run to see if you were using a
>> value that was not the fast-path one.
>>
>> The thing that I don't know if there's a solution for is the nesting
>> problem.  i.e., can you effectively distinguish:
>>
>>   Ok (Ok (Error x))
>>
>> from
>>
>>   Error x
>>
>> since they would have the same physical representation.  I'm not sure
>> if some variant of the counting trick used for options would work here
>> or not.  But if you could get this, it would make it possible to avoid
>> a large number of dirty Obj.magic hacks that people need to do to
>> build efficient datastructures in practice.  The fact that the stdlib
>> needs to use Obj.magic to get the necessary performance is, I think, a
>> sign that something important is missing from the language.  I'm not
>> sure if this is quite it, to be clear.
>
> Maybe I'm stating the obvious, but wouldn't value types be the general
> solution here? Assuming the optimizer can guarantee that the option
> value will not outlive the current scope, the value can be allocated on
> the stack or in registers. That's probably fast enough for most uses,
> isn't it? I think rust deals with option values exactly this way.
>
>
> --
> Simon

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

* RE: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17  9:10       ` Gabriel Scherer
  2014-01-17  9:22         ` Simon Cruanes
@ 2014-01-18  1:01         ` Jon Harrop
  2014-01-24 10:06         ` Alain Frisch
  2 siblings, 0 replies; 53+ messages in thread
From: Jon Harrop @ 2014-01-18  1:01 UTC (permalink / raw)
  To: 'Gabriel Scherer', 'David House'
  Cc: 'Julien Blond', 'Damien Guichard',
	'Caml Mailing List'

> The OCaml GC is very good at optimizing *short-lived* allocations

I see lots of people still asserting that. I think it needs quantifying.
AFAIK, OCaml's GC makes short-lived values 2-3x faster than long lived
values or malloc/free but removing unnecessary short lived allocations can
often make a function several times faster. So I think there is every reason
to optimize away allocations even if they are short-lived. Obvious examples
include optional arguments, options, tuples and complex numbers.

> Hopefully in fifteen years we'll be using programming languages with
well-typed strong update such as Mezzo ( http://protz.github.io/mezzo/ ),
that can solve this problem without any kind of ad-hoc optimization.

FWIW, I think value types and reified generics already solved this problem
(and many other related problems).

Cheers,
Jon.

-----Original Message-----
From: caml-list-request@inria.fr [mailto:caml-list-request@inria.fr] On
Behalf Of Gabriel Scherer
Sent: 17 January 2014 09:10
To: David House
Cc: Julien Blond; Damien Guichard; Caml Mailing List
Subject: Re: [Caml-list] How much optimized is the 'a option type ?

There have been recurrent discussions of optimizing `'a option` to avoid
allocation in some cases, which is interesting when it is used as a default
value for example. (The nice recent blog post by Thomas Leonard also seems
to assume that `'a option` is somehow optimized.)

My strictly personal opinion is that I doubt this would be a good idea,
because I expect a fair share of the programming practice that currently use
('a option) to move to something like (('a,
error-description) either) later in their lifetime, and I wouldn't want
people to avoid to do that for performance concerns.
Historically, we've rather come to see special-case representation
optimizations (eg. array of floats) as a mistake -- but on the other hand
there is not much downside to record of floats.

The OCaml GC is very good at optimizing *short-lived* allocations, so many
idiomatic uses of option are in fact already quite fast despite the
allocation. Using an `'a option array` for values that start undefined is
not one of such cases. Hopefully in fifteen years we'll be using programming
languages with well-typed strong update such as Mezzo (
http://protz.github.io/mezzo/ ), that can solve this problem without any
kind of ad-hoc optimization.

On Fri, Jan 17, 2014 at 9:40 AM, David House <dhouse@janestreet.com> wrote:
> Err, right, sorry. If you have None in, say, a record, that's not 
> allocated at all. Rather than there being a pointer in that field, 
> there is special word in that field which represents None.
>
> If that field is a Some, then it's a pointer to a two word allocated 
> block which in turn points at the actual thing. So compared to a C 
> pointer, there an extra two words and one more indirection.
>
>
> On 17 January 2014 08:16, Julien Blond <julien.blond@gmail.com> wrote:
>>
>> > An option value always takes two words: one for the header, and 
>> > then either a pointer or a word that means "None".
>>
>> No. From the reference manual § 19.3.4 :
>>
>> type 'a option = None           (* Val_int(0), i.e. just an integer value
>> = 1 word *)
>>                      | Some of 'a   (* block of size 1 = [(header = 1
>> word) + (1 field = 1 word)] = 2 words *)
>>
>>
>> 2014/1/17 David House <dhouse@janestreet.com>
>>>
>>> It behaves identically to that type.
>>>
>>> It is just like any other sum type. However, due to the way that sum 
>>> types are represented in memory, it is not that inefficient. The 
>>> only thing that makes it less efficient than a C pointer is the 
>>> header block (necessary for the GC). An option value always takes 
>>> two words: one for the header, and then either a pointer or a word that
means "None".
>>>
>>>
>>> On 17 January 2014 07:35, Damien Guichard <alphablock@orange.fr> wrote:
>>>>
>>>> Hello,
>>>>
>>>> Compared to the code :
>>>>
>>>> type 'a option = None | Some of 'a
>>>>
>>>> How do an 'a option value performs ?
>>>> Any allocation saved ?
>>>> Any indirection removed ?
>>>>
>>>> Is 'a option just like any sum type ?
>>>> Or is 'a option more like an ANSI C pointer type ?
>>>>
>>>> Regards,
>>>>
>>>> Damien Guichard
>>>>
>>>>
>>>>
>>>> --
>>>> Caml-list mailing list.  Subscription management and archives:
>>>> https://sympa.inria.fr/sympa/arc/caml-list
>>>> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
>>>> Bug reports: http://caml.inria.fr/bin/caml-bugs
>>>
>>>
>>
>

--
Caml-list mailing list.  Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs=


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

* RE: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17 11:23           ` Jonathan Kimmitt
  2014-01-17 13:46             ` Nicolas Braud-Santoni
@ 2014-01-18  1:18             ` Jon Harrop
  2014-01-20 10:16             ` Goswin von Brederlow
  2 siblings, 0 replies; 53+ messages in thread
From: Jon Harrop @ 2014-01-18  1:18 UTC (permalink / raw)
  To: 'Jonathan Kimmitt', caml-list

Jonathan Kimmitt wrote:
> If you compare this behaviour with the inferior clone F# written by
Microsoft,
> you can see that one of the things they added to the language was a nil
> pointer, thus abandoning all type safety immediately and all because they
> did not want to change their .NET runtime system for C# etc.

F# has a very good FFI to C#. In particular, it is memory safe. F# has null
because it is required for interop with C#. Idiomatic F# code does not use
null. Compare with OCaml's memory-unsafe FFI to C...

> They also have the notion of initialising a typed object to in an invalid
default,
> which is another obvious disaster area.

When you dequeue an element from a mutable queue that is represented
internally as an over-sized array you need to null-out the removed element
or you leak everything reachable from that value that would otherwise be
unreachable. F# uses Unchecked.defaultof<_> to create a default value of any
type (even a value type). The Queue module in the OCaml stdlib uses
"Obj.magic None" which works because OCaml doesn't have value types.

> Oh and did I mention operators like +/- etc are overloaded so you cannot
> infer function types without adding type annotations.

In F# the same arithmetic operators work transparently on the byte, sbyte,
uint16, int16, uint32, int32, uint64, int64, float, float32, BigInteger and
BigRational types as well as decimal, DateTime, vectors, matrices and
user-defined types. OCaml has + for int, +. for float and +/ for big
rationals and no other numeric types. Imagine what would happen if OCaml
supported just the full complement of numeric types, let alone the others?
You'd need 15 different operators just to support the numeric types I
listed...

> The final insult is to make indentation significant in the syntax so that
if
> you post a program to a list which does not respect whitespace (for
> example using a well-known Microsoft mail client), it completely destroys
> the meaning of the program.

I agree. :-)

Cheers,
Jon.

-----Original Message-----
From: caml-list-request@inria.fr [mailto:caml-list-request@inria.fr] On
Behalf Of Jonathan Kimmitt
Sent: 17 January 2014 11:24
To: caml-list@inria.fr
Subject: Re: [Caml-list] How much optimized is the 'a option type ?

In my humble opinion the main purpose of Some _ | None is to avoid the
requirement for a nil pointer in OCaml. If an external function wants to
return nil in order to indicate, for example that a certain resource is not
available, it can return None instead and this prevents dereferencing a nil
pointer in OCaml because the None cannot be dereferenced. If you compare
this behaviour with the inferior clone F# written by Microsoft, you can see
that one of the things they added to the language was a nil pointer, thus
abandoning all type safety immediately and all because they did not want to
change their .NET runtime system for C# etc. They also have the notion of
initialising a typed object to in an invalid default, which is another
obvious disaster area. Oh and did I mention operators like +/- etc are
overloaded so you cannot infer function types without adding type
annotations.
The final insult is to make indentation significant in the syntax so that if
you post a program to a list which does not respect whitespace (for example
using a well-known Microsoft mail client), it completely destroys the
meaning of the program.

I'm sure the authors of F# have their reasons for making all these changes,
and I'm not one to stand in the way of progress, and I don't set out to
offend anybody, but I think they got it wrong ...

--
Caml-list mailing list.  Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs


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

* RE: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17 14:02               ` Yaron Minsky
  2014-01-17 14:09                 ` Simon Cruanes
  2014-01-17 14:24                 ` Gabriel Scherer
@ 2014-01-18  1:27                 ` Jon Harrop
  2 siblings, 0 replies; 53+ messages in thread
From: Jon Harrop @ 2014-01-18  1:27 UTC (permalink / raw)
  To: 'Yaron Minsky', 'Nicolas Braud-Santoni'; +Cc: caml-list


What if you unbox locals and box only when a value is written into the heap?

Consider your type:

type ('a,'b) result =
     | Ok of 'a
     | Error of 'b

The representation could be a bit tag, an 'a and a 'b. These three would be
passed into a function as three separate arguments etc.

In essence, the representation is the value type bit * 'a * 'b while the
value is local (a function parameter, a local variable, a return value) and
the usual boxed representation when it is written into the heap.

I actually wanted to try implementing this representation in HLVM...

Cheers,
Jon.

-----Original Message-----
From: caml-list-request@inria.fr [mailto:caml-list-request@inria.fr] On
Behalf Of Yaron Minsky
Sent: 17 January 2014 14:02
To: Nicolas Braud-Santoni
Cc: caml-list@inria.fr
Subject: Re: [Caml-list] How much optimized is the 'a option type ?

I also agree with Gabriel that an option-specific optimization is not
clearly the right move.

But I wonder if a more general optimization that provided the possibility of
minting "fast-path" variants.  i.e., one could have an annotation that
marked a given branch of a variant as the "no-indirection" one, i.e., the
one that doesn't lead to the allocation of an extra block:

type ('a,'b) result =
     | Ok of 'a [@@no_indirection]
     | Error of 'b

would lead to a type where [Ok x == x].  Some cleverness is required then
for the representation of the [Error] branch.  In particular, you'd need
some dynamic test you could run to see if you were using a value that was
not the fast-path one.

The thing that I don't know if there's a solution for is the nesting
problem.  i.e., can you effectively distinguish:

  Ok (Ok (Error x))

from

  Error x

since they would have the same physical representation.  I'm not sure if
some variant of the counting trick used for options would work here or not.
But if you could get this, it would make it possible to avoid a large number
of dirty Obj.magic hacks that people need to do to build efficient
datastructures in practice.  The fact that the stdlib needs to use Obj.magic
to get the necessary performance is, I think, a sign that something
important is missing from the language.  I'm not sure if this is quite it,
to be clear.

y


On Fri, Jan 17, 2014 at 8:46 AM, Nicolas Braud-Santoni
<nicolas.braudsantoni@gmail.com> wrote:
> On 17/01/2014 12:23, Jonathan Kimmitt wrote:
>> In my humble opinion the main purpose of Some _ | None is to avoid 
>> the requirement for a nil pointer in OCaml. If an external function 
>> wants to return nil in order to indicate, for example that a certain 
>> resource is not available, it can return None instead and this 
>> prevents dereferencing a nil pointer in OCaml because the None cannot be
dereferenced.
> Yes.
> This doesn't forbid the compiler from representing 'a option values as 
> pointers.
> Indeed, the type system already enforces that the None case is handled 
> and the representation of None and Some _ do not matter.
>
> That said, I agree with Gabriel Scherer : adding optimizations 
> specific to 'a option might refrain people wanting to switch to more 
> appropriate datatypes.
> However, would is be possible to "optimize away" all types of the form 
> "type 'a t = X of 'a | A | B | ..." (with at most one non-constant
> constructor) ?
> Would it be worth doing ?
>
>
> Kind regards,
> Nicolas
>

--
Caml-list mailing list.  Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs=


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

* RE: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17 17:57           ` Gerd Stolpmann
@ 2014-01-18  1:35             ` Jon Harrop
  2014-01-19  6:19               ` oleg
  0 siblings, 1 reply; 53+ messages in thread
From: Jon Harrop @ 2014-01-18  1:35 UTC (permalink / raw)
  To: 'Gerd Stolpmann', 'Simon Cruanes'
  Cc: 'Gabriel Scherer', 'David House',
	'Julien Blond', 'Damien Guichard',
	'Caml Mailing List'

Gerd wrote:
> Gabriel is right that the GC is good at short-living values, but that
> still leaves room for getting better with ultra-short-living values.

FWIW, the largest benefit of value types is in improving the topology of the
heap for long-lived values rather than for stack-allocating short-lived
values. For example, value types facilitate much more efficient generic hash
tables.

Cheers,
Jon.

-----Original Message-----
From: caml-list-request@inria.fr [mailto:caml-list-request@inria.fr] On
Behalf Of Gerd Stolpmann
Sent: 17 January 2014 17:57
To: Simon Cruanes
Cc: Gabriel Scherer; David House; Julien Blond; Damien Guichard; Caml
Mailing List
Subject: Re: [Caml-list] How much optimized is the 'a option type ?

Am Freitag, den 17.01.2014, 10:22 +0100 schrieb Simon Cruanes:
> Le Fri, 17 Jan 2014, Gabriel Scherer a écrit :
> 
> > There have been recurrent discussions of optimizing `'a option` to 
> > avoid allocation in some cases, which is interesting when it is used 
> > as a default value for example. (The nice recent blog post by Thomas 
> > Leonard also seems to assume that `'a option` is somehow optimized.)
> > 
> > My strictly personal opinion is that I doubt this would be a good 
> > idea, because I expect a fair share of the programming practice that 
> > currently use ('a option) to move to something like (('a,
> > error-description) either) later in their lifetime, and I wouldn't 
> > want people to avoid to do that for performance concerns.
> > Historically, we've rather come to see special-case representation 
> > optimizations (eg. array of floats) as a mistake -- but on the other 
> > hand there is not much downside to record of floats.
> 
> I think optimization of some local uses of options, such as:

I also think that local uses of options (and other variant types) could be
candidates for optimization. Gabriel is right that the GC is good at
short-living values, but that still leaves room for getting better with
ultra-short-living values.

My idea would be to try to delay the allocation of the block, and to use two
registers, i.e. one for the tag, and one for the tagged inner value.
First when the constructed value is passed to some other function, or
returned, or stored inside another block, or in another register, the
allocation is really done. Of course, this could also result in more work in
total (especially when the compiler has no idea what the desired fast path
of the algorithm is), and I guess the real problem is that you need a good
heuristics to decide when to do this. But there are at least two criterions
at hand:

 - You are not under pressure with registers
 - All consumers of the constructed value are inside the same function

I guess this would result in a quite heavy patch for the comparatively small
effect, and that's why it is not yet done.


Gerd


> let rec iter_stream f s =
>     match (try Some (MyStream.get s) with End_of_stream -> None) with
>     | None -> ()
>     | Some (x, s') ->
>         f x;
>         iter_stream f s'
> 
> where an option is used to keep the function tail-rec (I've heard 
> several people tell me they often need to use this), or other cases 
> like optional parameters (which are not going to move to Either), 
> would be useful and future-proof. I hope the current work on 
> optimizations will help with this kind of cases (removing useless 
> allocations of local options, references, exceptions when no escape is
possible).
> 
> </wishlist>
> </2cents>
> </</>>
> 

--
------------------------------------------------------------
Gerd Stolpmann, Darmstadt, Germany    gerd@gerd-stolpmann.de
My OCaml site:          http://www.camlcity.org
Contact details:        http://www.camlcity.org/contact.html
Company homepage:       http://www.gerd-stolpmann.de
------------------------------------------------------------



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

* RE: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17 14:09                 ` Simon Cruanes
  2014-01-17 22:52                   ` Yaron Minsky
@ 2014-01-18  1:37                   ` Jon Harrop
  1 sibling, 0 replies; 53+ messages in thread
From: Jon Harrop @ 2014-01-18  1:37 UTC (permalink / raw)
  To: 'Simon Cruanes', 'Yaron Minsky'
  Cc: 'Nicolas Braud-Santoni', caml-list

Simon Cruanes wrote:
> Maybe I'm stating the obvious, but wouldn't value types be the general solution here?

Yes but value types conflict with a uniform data representation. I think OCaml has reached a local optimum here...

Cheers,
Jon.

-----Original Message-----
From: caml-list-request@inria.fr [mailto:caml-list-request@inria.fr] On Behalf Of Simon Cruanes
Sent: 17 January 2014 14:10
To: Yaron Minsky
Cc: Nicolas Braud-Santoni; caml-list@inria.fr
Subject: Re: [Caml-list] How much optimized is the 'a option type ?

Le Fri, 17 Jan 2014, Yaron Minsky a écrit :
> I also agree with Gabriel that an option-specific optimization is not 
> clearly the right move.
> 
> But I wonder if a more general optimization that provided the 
> possibility of minting "fast-path" variants.  i.e., one could have an 
> annotation that marked a given branch of a variant as the 
> "no-indirection" one, i.e., the one that doesn't lead to the 
> allocation of an extra block:
> 
> type ('a,'b) result =
>      | Ok of 'a [@@no_indirection]
>      | Error of 'b
> 
> would lead to a type where [Ok x == x].  Some cleverness is required 
> then for the representation of the [Error] branch.  In particular, 
> you'd need some dynamic test you could run to see if you were using a 
> value that was not the fast-path one.
> 
> The thing that I don't know if there's a solution for is the nesting 
> problem.  i.e., can you effectively distinguish:
> 
>   Ok (Ok (Error x))
> 
> from
> 
>   Error x
> 
> since they would have the same physical representation.  I'm not sure 
> if some variant of the counting trick used for options would work here 
> or not.  But if you could get this, it would make it possible to avoid 
> a large number of dirty Obj.magic hacks that people need to do to 
> build efficient datastructures in practice.  The fact that the stdlib 
> needs to use Obj.magic to get the necessary performance is, I think, a 
> sign that something important is missing from the language.  I'm not 
> sure if this is quite it, to be clear.

Maybe I'm stating the obvious, but wouldn't value types be the general solution here? Assuming the optimizer can guarantee that the option value will not outlive the current scope, the value can be allocated on the stack or in registers. That's probably fast enough for most uses, isn't it? I think rust deals with option values exactly this way.


--
Simon


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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-18  1:35             ` Jon Harrop
@ 2014-01-19  6:19               ` oleg
  2014-01-21  1:51                 ` Francois Berenger
  0 siblings, 1 reply; 53+ messages in thread
From: oleg @ 2014-01-19  6:19 UTC (permalink / raw)
  To: caml-list


> let rec iter_stream f s =
>     match (try Some (MyStream.get s) with End_of_stream -> None) with
>     | None -> ()
>     | Some (x, s') ->
>         f x;
>         iter_stream f s'
>
> where an option is used to keep the function tail-rec (I've heard
> several people tell me they often need to use this), or other cases
> like optional parameters (which are not going to move to Either),
> would be useful and future-proof. 

I concur this is a very common pattern. The immediate thought is that
perhaps functions like MyStream.get should return an (('result,'error)
either) value rather than throw an exception. But there is a better
solution, described in

        Exceptional Syntax 
        Nick Benton and Andrew Kennedy. 
        In Journal of Functional Programming, 11(4):
        395-410, July 2001.
        http://research.microsoft.com/en-us/um/people/akenn/sml/ExceptionalSyntax.pdf

Incidentally, the example presented in Sec 3 of the paper is almost
exactly like the example mentioned on this thread. It is a common
problem, and luckily a good solution has been designed and well
explained. I guess what's lacking is time to implement it.





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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17 14:36 ` Markus Mottl
  2014-01-17 15:49   ` Yotam Barnoy
@ 2014-01-20 10:09   ` Goswin von Brederlow
  1 sibling, 0 replies; 53+ messages in thread
From: Goswin von Brederlow @ 2014-01-20 10:09 UTC (permalink / raw)
  To: caml-list

On Fri, Jan 17, 2014 at 09:36:22AM -0500, Markus Mottl wrote:
> Others have already answered about memory representation, but there is
> one thing about allocations that many OCaml programmers may not yet be
> aware of and that can make a noticeable performance difference when
> used wisely: the OCaml compiler will inspect your code and, under the
> right conditions, batch together allocations.  E.g. consider this
> function (references are records, btw.):
> 
>   let f n =
>     let x = ref (ref (Some (Some n))) in
>     [(x, n); (x, n)]
> 
> One might naively assume that this would lead to seven or so
> allocations.  But if you inspect the assembly, you'll see only one
> allocation followed by mere initialization assignments.

Cool. Didn't know that. Thanks for whoever implemented that.

MfG
	Goswin

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17 11:23           ` Jonathan Kimmitt
  2014-01-17 13:46             ` Nicolas Braud-Santoni
  2014-01-18  1:18             ` Jon Harrop
@ 2014-01-20 10:16             ` Goswin von Brederlow
  2014-01-20 11:23               ` Jonathan Kimmitt
  2014-01-22 21:26               ` Jon Harrop
  2 siblings, 2 replies; 53+ messages in thread
From: Goswin von Brederlow @ 2014-01-20 10:16 UTC (permalink / raw)
  To: caml-list

On Fri, Jan 17, 2014 at 12:23:32PM +0100, Jonathan Kimmitt wrote:
> In my humble opinion the main purpose of Some _ | None is to avoid the
> requirement for a nil pointer in OCaml. If an external function wants to
> return nil in order to indicate, for example that a certain resource is not
> available, it can return None instead and this prevents dereferencing a nil
> pointer in OCaml because the None cannot be dereferenced. If you compare this
> behaviour with the inferior clone F# written by Microsoft, you can see that
> one of the things they added to the language was a nil pointer, thus
> abandoning all type safety immediately and all because they did not want to
> change their .NET runtime system for C# etc. They also have the notion of
> initialising a typed object to in an invalid default, which is another obvious
> disaster area. Oh and did I mention operators like +/- etc are overloaded so
> you cannot infer function types without adding type annotations.
> The final insult is to make indentation significant in the syntax so that if
> you post a program to a list which does not respect whitespace (for example
> using a well-known Microsoft mail client), it completely destroys the meaning
> of the program.
> 
> I'm sure the authors of F# have their reasons for making all these changes,
> and I'm not one to stand in the way of progress, and I don't set out to offend
> anybody, but I think they got it wrong ...

You could use the following representaion for 'a option:

None -> NULL pointer
Some x -> value x (meaning pointer for complex types, tagged integer eles)

This looks fine at first and typesafe. A pointer can never be NULL,
same for a tagged integer. BUT

None -> NULL
Some None -> NULL
Some Some x -> value x

You could no longer have 'a option option types. In F#, with nil
pointer, that will be a problem. But I guess nobody ever has 'a option
option types there.

MfG
	Goswin

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-20 10:16             ` Goswin von Brederlow
@ 2014-01-20 11:23               ` Jonathan Kimmitt
  2014-01-21  2:05                 ` Francois Berenger
  2014-01-22 21:26               ` Jon Harrop
  1 sibling, 1 reply; 53+ messages in thread
From: Jonathan Kimmitt @ 2014-01-20 11:23 UTC (permalink / raw)
  To: caml-list

OCaml already uses the number 1 to represent
0(sic), [], and None. Type safety prevents them getting mixed up.
The integer 1 would be represented by 3, and so on. Since pointers
are always even (on sensible platforms) this helps the garbage collector
to quickly scan without caring too much about what it all means.

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-19  6:19               ` oleg
@ 2014-01-21  1:51                 ` Francois Berenger
  0 siblings, 0 replies; 53+ messages in thread
From: Francois Berenger @ 2014-01-21  1:51 UTC (permalink / raw)
  To: caml-list

On 01/19/2014 03:19 PM, oleg@okmij.org wrote:
>> let rec iter_stream f s =
>>      match (try Some (MyStream.get s) with End_of_stream -> None) with
>>      | None -> ()
>>      | Some (x, s') ->
>>          f x;
>>          iter_stream f s'
>>
>> where an option is used to keep the function tail-rec (I've heard
>> several people tell me they often need to use this), or other cases
>> like optional parameters (which are not going to move to Either),
>> would be useful and future-proof.
>
> I concur this is a very common pattern.

Almost the whole List module in batteries is written in this style,
to avoid reverting lists but keeping tail-rec functions which are not
when implemented naively.


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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-20 11:23               ` Jonathan Kimmitt
@ 2014-01-21  2:05                 ` Francois Berenger
  2014-01-22 21:22                   ` Jon Harrop
  0 siblings, 1 reply; 53+ messages in thread
From: Francois Berenger @ 2014-01-21  2:05 UTC (permalink / raw)
  To: caml-list

Isn't this thread about people wanting to have monadic code
in OCaml going faster?

Someone has in mind some optimization that would make
all monadic code faster, right?
Not only the 'a option case, I hope.

On 01/20/2014 08:23 PM, Jonathan Kimmitt wrote:
> OCaml already uses the number 1 to represent
> 0(sic), [], and None. Type safety prevents them getting mixed up.
> The integer 1 would be represented by 3, and so on. Since pointers
> are always even (on sensible platforms) this helps the garbage collector
> to quickly scan without caring too much about what it all means.

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

* RE: [Caml-list] How much optimized is the 'a option type ?
  2014-01-21  2:05                 ` Francois Berenger
@ 2014-01-22 21:22                   ` Jon Harrop
  0 siblings, 0 replies; 53+ messages in thread
From: Jon Harrop @ 2014-01-22 21:22 UTC (permalink / raw)
  To: 'Francois Berenger', caml-list

Francois wrote:
> Isn't this thread about people wanting to have monadic code in OCaml going
faster?

I think you would need the equivalent optimizations applied to closures
which begs the question: how do you represent closures using value types?

Cheers,
Jon.



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

* RE: [Caml-list] How much optimized is the 'a option type ?
  2014-01-20 10:16             ` Goswin von Brederlow
  2014-01-20 11:23               ` Jonathan Kimmitt
@ 2014-01-22 21:26               ` Jon Harrop
  2014-01-23  9:29                 ` Goswin von Brederlow
  1 sibling, 1 reply; 53+ messages in thread
From: Jon Harrop @ 2014-01-22 21:26 UTC (permalink / raw)
  To: 'Goswin von Brederlow', caml-list

Goswin wrote:
> In F#, with nil pointer, that will be a problem. But I guess nobody ever
has 'a option option types there

I believe the representation of Some None in F# is a heap allocated block
containing a NULL pointer.

Cheers,
Jon.

-----Original Message-----
From: caml-list-request@inria.fr [mailto:caml-list-request@inria.fr] On
Behalf Of Goswin von Brederlow
Sent: 20 January 2014 10:17
To: caml-list@inria.fr
Subject: Re: [Caml-list] How much optimized is the 'a option type ?

On Fri, Jan 17, 2014 at 12:23:32PM +0100, Jonathan Kimmitt wrote:
> In my humble opinion the main purpose of Some _ | None is to avoid the 
> requirement for a nil pointer in OCaml. If an external function wants 
> to return nil in order to indicate, for example that a certain 
> resource is not available, it can return None instead and this 
> prevents dereferencing a nil pointer in OCaml because the None cannot 
> be dereferenced. If you compare this behaviour with the inferior clone 
> F# written by Microsoft, you can see that one of the things they added 
> to the language was a nil pointer, thus abandoning all type safety 
> immediately and all because they did not want to change their .NET 
> runtime system for C# etc. They also have the notion of initialising a 
> typed object to in an invalid default, which is another obvious 
> disaster area. Oh and did I mention operators like +/- etc are overloaded
so you cannot infer function types without adding type annotations.
> The final insult is to make indentation significant in the syntax so 
> that if you post a program to a list which does not respect whitespace 
> (for example using a well-known Microsoft mail client), it completely 
> destroys the meaning of the program.
> 
> I'm sure the authors of F# have their reasons for making all these 
> changes, and I'm not one to stand in the way of progress, and I don't 
> set out to offend anybody, but I think they got it wrong ...

You could use the following representaion for 'a option:

None -> NULL pointer
Some x -> value x (meaning pointer for complex types, tagged integer eles)

This looks fine at first and typesafe. A pointer can never be NULL, same for
a tagged integer. BUT

None -> NULL
Some None -> NULL
Some Some x -> value x

You could no longer have 'a option option types. In F#, with nil pointer,
that will be a problem. But I guess nobody ever has 'a option option types
there.

MfG
	Goswin

--
Caml-list mailing list.  Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs


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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-22 21:26               ` Jon Harrop
@ 2014-01-23  9:29                 ` Goswin von Brederlow
  2014-01-23 23:20                   ` Jon Harrop
  0 siblings, 1 reply; 53+ messages in thread
From: Goswin von Brederlow @ 2014-01-23  9:29 UTC (permalink / raw)
  To: caml-list

On Wed, Jan 22, 2014 at 09:26:09PM -0000, Jon Harrop wrote:
> Goswin wrote:
> > In F#, with nil pointer, that will be a problem. But I guess nobody ever
> has 'a option option types there
> 
> I believe the representation of Some None in F# is a heap allocated block
> containing a NULL pointer.
> 
> Cheers,
> Jon.

So Some x is the value x unless x is an option type? That wouldn't
work for polymorphic functions, those taking 'a option. You can't
encode 'a option differently depending on 'a unless you have a flag
for which encoding it used as well.

I think you can only have one: option types using nil or 'a option
option.

Which doesn't mean you can't have nil too, just not to represent the
None part of 'a option. In ocaml you would need a new type syntax like

type 'a ptr_option = NIL | PTR of 'a constraint type b . 'a != b ptr_option

MfG
	Goswin

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

* RE: [Caml-list] How much optimized is the 'a option type ?
  2014-01-23  9:29                 ` Goswin von Brederlow
@ 2014-01-23 23:20                   ` Jon Harrop
  2014-01-23 23:28                     ` Yotam Barnoy
  0 siblings, 1 reply; 53+ messages in thread
From: Jon Harrop @ 2014-01-23 23:20 UTC (permalink / raw)
  To: 'Goswin von Brederlow', caml-list

Goswin wrote:
> So Some x is the value x unless x is an option type?

No, Some x is always a reference to a heap-allocated object that contains
the value "x".

In fact, I think it is essentially the same as OCaml's representation for
the 'a option type (except for the run-time "type" information required by
the GC).

> You can't encode 'a option differently depending on 'a unless you have a
flag for which encoding it used as well.

Yes. I think it is a bad data representation though. Option types should
never allocate anything at all. They should be a value type containing a
boolean "HasValue" and the value itself which has a default in the event
that it is None. So None=(false, _), Some 3=(true, 3), Some None=(true,
(false, _)) and Some(Some 3)=(true, (true, 3)). You could even store the
Booleans and bytes as pack them so Some(Some 3) would take the same amount
of space (16 bytes) as Some 3.

Cheers,
Jon.

-----Original Message-----
From: caml-list-request@inria.fr [mailto:caml-list-request@inria.fr] On
Behalf Of Goswin von Brederlow
Sent: 23 January 2014 09:29
To: caml-list@inria.fr
Subject: Re: [Caml-list] How much optimized is the 'a option type ?

On Wed, Jan 22, 2014 at 09:26:09PM -0000, Jon Harrop wrote:
> Goswin wrote:
> > In F#, with nil pointer, that will be a problem. But I guess nobody 
> > ever
> has 'a option option types there
> 
> I believe the representation of Some None in F# is a heap allocated 
> block containing a NULL pointer.
> 
> Cheers,
> Jon.

So Some x is the value x unless x is an option type? That wouldn't work for
polymorphic functions, those taking 'a option. You can't encode 'a option
differently depending on 'a unless you have a flag for which encoding it
used as well.

I think you can only have one: option types using nil or 'a option option.

Which doesn't mean you can't have nil too, just not to represent the None
part of 'a option. In ocaml you would need a new type syntax like

type 'a ptr_option = NIL | PTR of 'a constraint type b . 'a != b ptr_option

MfG
	Goswin

--
Caml-list mailing list.  Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs


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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-23 23:20                   ` Jon Harrop
@ 2014-01-23 23:28                     ` Yotam Barnoy
  2014-01-24  8:22                       ` Jon Harrop
  0 siblings, 1 reply; 53+ messages in thread
From: Yotam Barnoy @ 2014-01-23 23:28 UTC (permalink / raw)
  To: Jon Harrop; +Cc: Goswin von Brederlow, Ocaml Mailing List

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

Just to clarify, by value types you mean stuff allocated on the stack,
right?

-Yotam


On Thu, Jan 23, 2014 at 6:20 PM, Jon Harrop <jon@ffconsultancy.com> wrote:

> Goswin wrote:
> > So Some x is the value x unless x is an option type?
>
> No, Some x is always a reference to a heap-allocated object that contains
> the value "x".
>
> In fact, I think it is essentially the same as OCaml's representation for
> the 'a option type (except for the run-time "type" information required by
> the GC).
>
> > You can't encode 'a option differently depending on 'a unless you have a
> flag for which encoding it used as well.
>
> Yes. I think it is a bad data representation though. Option types should
> never allocate anything at all. They should be a value type containing a
> boolean "HasValue" and the value itself which has a default in the event
> that it is None. So None=(false, _), Some 3=(true, 3), Some None=(true,
> (false, _)) and Some(Some 3)=(true, (true, 3)). You could even store the
> Booleans and bytes as pack them so Some(Some 3) would take the same amount
> of space (16 bytes) as Some 3.
>
> Cheers,
> Jon.
>
> -----Original Message-----
> From: caml-list-request@inria.fr [mailto:caml-list-request@inria.fr] On
> Behalf Of Goswin von Brederlow
> Sent: 23 January 2014 09:29
> To: caml-list@inria.fr
> Subject: Re: [Caml-list] How much optimized is the 'a option type ?
>
> On Wed, Jan 22, 2014 at 09:26:09PM -0000, Jon Harrop wrote:
> > Goswin wrote:
> > > In F#, with nil pointer, that will be a problem. But I guess nobody
> > > ever
> > has 'a option option types there
> >
> > I believe the representation of Some None in F# is a heap allocated
> > block containing a NULL pointer.
> >
> > Cheers,
> > Jon.
>
> So Some x is the value x unless x is an option type? That wouldn't work for
> polymorphic functions, those taking 'a option. You can't encode 'a option
> differently depending on 'a unless you have a flag for which encoding it
> used as well.
>
> I think you can only have one: option types using nil or 'a option option.
>
> Which doesn't mean you can't have nil too, just not to represent the None
> part of 'a option. In ocaml you would need a new type syntax like
>
> type 'a ptr_option = NIL | PTR of 'a constraint type b . 'a != b ptr_option
>
> MfG
>         Goswin
>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>
>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>

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

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

* RE: [Caml-list] How much optimized is the 'a option type ?
  2014-01-23 23:28                     ` Yotam Barnoy
@ 2014-01-24  8:22                       ` Jon Harrop
  2014-01-24  8:34                         ` Andreas Rossberg
  2014-01-27 10:03                         ` Goswin von Brederlow
  0 siblings, 2 replies; 53+ messages in thread
From: Jon Harrop @ 2014-01-24  8:22 UTC (permalink / raw)
  To: 'Yotam Barnoy'
  Cc: 'Goswin von Brederlow', 'Ocaml Mailing List'

Yotam wrote:
> Just to clarify, by value types you mean stuff allocated on the stack,
right?

A value type is just an unboxed type like a C struct. A local variable of a
value type is stored on the stack. A field inside a heap-allocated object
that is a value type is stored inside the object and not in a separate
object. An array of value types is a single contiguous block of memory with
no pointers (e.g. an array of complex numbers).

With value types you can almost completely avoid the garbage collector by
replacing pointers with indices into an array of value types that acts as a
pool allocator. This can be useful for avoiding GC latency and for
optimizing for collections that violate the generational hypothesis (e.g.
long-lived Sets and Maps).

In HLVM, tuples were value types. For example, an (int * float) array is
represented as a single contiguous block of memory. In constrast, OCaml
represents this is an array of pointers to pairs where the second element is
another pointer to a boxed float.

Value types and reified generics permit very efficient hash tables. For
example, the Dictionary<int, float> type on .NET does not contain any
pointers.

Cheers,
Jon.



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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-24  8:22                       ` Jon Harrop
@ 2014-01-24  8:34                         ` Andreas Rossberg
  2014-01-24 16:56                           ` Jon Harrop
  2014-01-27 10:03                         ` Goswin von Brederlow
  1 sibling, 1 reply; 53+ messages in thread
From: Andreas Rossberg @ 2014-01-24  8:34 UTC (permalink / raw)
  To: jon; +Cc: Ocaml Mailing List

On Jan 24, 2014, at 09:22 , Jon Harrop <jon@ffconsultancy.com> wrote:
> With value types you can almost completely avoid the garbage collector by
> replacing pointers with indices into an array of value types that acts as a
> pool allocator. This can be useful for avoiding GC latency and for
> optimizing for collections that violate the generational hypothesis (e.g.
> long-lived Sets and Maps).

As you well know, though, pervasive unboxing as for value types is incompatible with a uniform representation approach like used by OCaml. And non-uniform representation requires either static monomorphisation (not possible in OCaml, because of first-class polymorphism and separate compilation), or dynamic monomorphisation (not possible without just-in-time compilation), or runtime type passing and switching (expensive).

/Andreas


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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-17  9:10       ` Gabriel Scherer
  2014-01-17  9:22         ` Simon Cruanes
  2014-01-18  1:01         ` Jon Harrop
@ 2014-01-24 10:06         ` Alain Frisch
  2014-01-24 10:16           ` Alain Frisch
  2 siblings, 1 reply; 53+ messages in thread
From: Alain Frisch @ 2014-01-24 10:06 UTC (permalink / raw)
  To: Gabriel Scherer, David House
  Cc: Julien Blond, Damien Guichard, Caml Mailing List

On 01/17/2014 10:10 AM, Gabriel Scherer wrote:
> There have been recurrent discussions of optimizing `'a option` to
> avoid allocation in some cases, which is interesting when it is used
> as a default value for example. (The nice recent blog post by Thomas
> Leonard also seems to assume that `'a option` is somehow optimized.)
>
> My strictly personal opinion is that I doubt this would be a good
> idea, because I expect a fair share of the programming practice that
> currently use ('a option) to move to something like (('a,
> error-description) either) later in their lifetime, and I wouldn't
> want people to avoid to do that for performance concerns.
> Historically, we've rather come to see special-case representation
> optimizations (eg. array of floats) as a mistake -- but on the other
> hand there is not much downside to record of floats.

It could be argued the role of option types is important enough to 
justify a special treatment for them.  But maybe one could think (just 
for the fun of it) about a more general optimized representation for sum 
types where one constructor should behave (mostly) as the identity at 
runtime.

To take an example, consider a type:

   type ('a, 'b) t =
      | A of 'a
      | B of 'b * 'b
      | C

with some marker to tell the compiler to optimize the representation of A.

If one wants the constructor A to be the identity at runtime (in most 
cases), we still need to distinguish C from A C, A (A C), A (A (A C)), 
etc,  and B (x, y) from A (B (x, y)), A (A (B (x, y))), etc.  Here is 
one possible implementation:  let's allocate a fresh value to represent 
the identity of the t type:

   id_t = 0:(0)

that is, a block of size 1, tag 0, with a single 0 field (equivalent to: 
id_t = ref ()).  (This value would be generated by the compiler and 
passed along in modules which re-export the type t.)

The value (B (x, y)) would be represented as a block b0 = 1:(id_t, 0, x, 
y)  (block with tag 1 and 4 fields).  Applying the A constructor to such 
a block b0 would return a new block b1 = 1:(id_t, b0).  Applying again 
the A constructor to b1 would return b2 = 1:(id_t, b1).

Similarly, the value C would be represented as a block c0 = 2:(id_t, 0). 
  Applying A to such a value would return a block c1 = 1:(id_t, c0), and 
then c2 = 1:(id_t, c1).

So, in general, applying the A constructor to a value x requires to 
check if its argument is a block whose first field is equal to id_t, and 
in this case, it returns a new block with the same tag and the two 
fields id_t and x.  In other cases, the constructors simply returns its 
argument.

With this representation, it is not difficult to deconstruct the three 
constructors.  For a value of type t:

  - If the value is a block whose first field is equal to id_t and its 
second field is 0, then the value comes from the B or C constructor 
(according to the block tag) and the arguments can be found in the block.

  - If the value is a block whose first first is equal to id_t and its 
second field is not 0, then the value comes from the A constructor, and 
the argument is the second field of the block.

  - Otherwise, the value comes from the A constructor and its argument 
is represented by the same value.


There is one correctness problem with this representation, though: 
applying the A constructor to a float value cannot be the identity, 
because of the specific representation for float arrays (which is 
triggered by checking if the value is a float block).  This means we 
must also have a special representation for A x, A (A x), etc, where x 
is a float.  The scheme above extends naturally to support this 
representation:  a0 = 0:(id_t, 0, x), a1 = 0:(id_t, a0), etc.


Another drawback is related to the use of the id_t block, which does not 
work well with the generic marshaling, and requires extra plumbing to 
make this value available where the type t can be constructed or 
deconstructed.  It's possible to do better for a type with a "global name".


In case of a constant constructor such as C, one can of course 
pre-allocate the block c0 = 2:(id_t, 0).  To avoid passing an extra 
value around, one could store it within id_t itself (id_t = 0:(c0) 
instead of id_t = 0:(0)).

Another optimization is to avoid the allocation when applying the A 
constructor several times to the same B or C value.  This can be done by 
memoization.  One can add an extra field to all the blocks described 
above, initialized to 0, and updated to point to the "next" application 
of A when requested.

So, we would have:

   c0 = 2:(id_t, 0, 0)

When applying A to it, one create c1

   c1 = 2:(id_t, c0, 0)

and update the last field of c0 to be c1:

   c0 = 2:(id_t, 0, c1)

If one needs to apply A again to c0, one can reuse the existing value. 
The same applies to non-constant constructors as well.



-- Alain

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-24 10:06         ` Alain Frisch
@ 2014-01-24 10:16           ` Alain Frisch
  2014-01-24 13:32             ` Yaron Minsky
  0 siblings, 1 reply; 53+ messages in thread
From: Alain Frisch @ 2014-01-24 10:16 UTC (permalink / raw)
  To: Gabriel Scherer, David House
  Cc: Julien Blond, Damien Guichard, Caml Mailing List

Revised description:  there is no need to keep the tag on B or C values 
when applying the A constructor, and one can skip the 0 integer as the 
second field when applying the B/C constructor.

    B (x, y)   ---->   b0 = 1:(id_t,x, y)
A (B (x, y))  ---->   b1 = 0:(id_t, b0)

    C          ---->   c0 = 2:(id_t)
A  C          ---->   c1 = 0:(id_t, c0)


This simplifies the criterion for checking if a value of type t has the 
B/C constructor (tag = 1 or 2) or the A constructor (tag = 0, and the 
argument is the second field of the block if the first is id_t, and the 
value itself otherwise).

-- Alain


On 01/24/2014 11:06 AM, Alain Frisch wrote:
> On 01/17/2014 10:10 AM, Gabriel Scherer wrote:
>> There have been recurrent discussions of optimizing `'a option` to
>> avoid allocation in some cases, which is interesting when it is used
>> as a default value for example. (The nice recent blog post by Thomas
>> Leonard also seems to assume that `'a option` is somehow optimized.)
>>
>> My strictly personal opinion is that I doubt this would be a good
>> idea, because I expect a fair share of the programming practice that
>> currently use ('a option) to move to something like (('a,
>> error-description) either) later in their lifetime, and I wouldn't
>> want people to avoid to do that for performance concerns.
>> Historically, we've rather come to see special-case representation
>> optimizations (eg. array of floats) as a mistake -- but on the other
>> hand there is not much downside to record of floats.
>
> It could be argued the role of option types is important enough to
> justify a special treatment for them.  But maybe one could think (just
> for the fun of it) about a more general optimized representation for sum
> types where one constructor should behave (mostly) as the identity at
> runtime.
>
> To take an example, consider a type:
>
>    type ('a, 'b) t =
>       | A of 'a
>       | B of 'b * 'b
>       | C
>
> with some marker to tell the compiler to optimize the representation of A.
>
> If one wants the constructor A to be the identity at runtime (in most
> cases), we still need to distinguish C from A C, A (A C), A (A (A C)),
> etc,  and B (x, y) from A (B (x, y)), A (A (B (x, y))), etc.  Here is
> one possible implementation:  let's allocate a fresh value to represent
> the identity of the t type:
>
>    id_t = 0:(0)
>
> that is, a block of size 1, tag 0, with a single 0 field (equivalent to:
> id_t = ref ()).  (This value would be generated by the compiler and
> passed along in modules which re-export the type t.)
>
> The value (B (x, y)) would be represented as a block b0 = 1:(id_t, 0, x,
> y)  (block with tag 1 and 4 fields).  Applying the A constructor to such
> a block b0 would return a new block b1 = 1:(id_t, b0).  Applying again
> the A constructor to b1 would return b2 = 1:(id_t, b1).
>
> Similarly, the value C would be represented as a block c0 = 2:(id_t, 0).
>   Applying A to such a value would return a block c1 = 1:(id_t, c0), and
> then c2 = 1:(id_t, c1).
>
> So, in general, applying the A constructor to a value x requires to
> check if its argument is a block whose first field is equal to id_t, and
> in this case, it returns a new block with the same tag and the two
> fields id_t and x.  In other cases, the constructors simply returns its
> argument.
>
> With this representation, it is not difficult to deconstruct the three
> constructors.  For a value of type t:
>
>   - If the value is a block whose first field is equal to id_t and its
> second field is 0, then the value comes from the B or C constructor
> (according to the block tag) and the arguments can be found in the block.
>
>   - If the value is a block whose first first is equal to id_t and its
> second field is not 0, then the value comes from the A constructor, and
> the argument is the second field of the block.
>
>   - Otherwise, the value comes from the A constructor and its argument
> is represented by the same value.
>
>
> There is one correctness problem with this representation, though:
> applying the A constructor to a float value cannot be the identity,
> because of the specific representation for float arrays (which is
> triggered by checking if the value is a float block).  This means we
> must also have a special representation for A x, A (A x), etc, where x
> is a float.  The scheme above extends naturally to support this
> representation:  a0 = 0:(id_t, 0, x), a1 = 0:(id_t, a0), etc.
>
>
> Another drawback is related to the use of the id_t block, which does not
> work well with the generic marshaling, and requires extra plumbing to
> make this value available where the type t can be constructed or
> deconstructed.  It's possible to do better for a type with a "global name".
>
>
> In case of a constant constructor such as C, one can of course
> pre-allocate the block c0 = 2:(id_t, 0).  To avoid passing an extra
> value around, one could store it within id_t itself (id_t = 0:(c0)
> instead of id_t = 0:(0)).
>
> Another optimization is to avoid the allocation when applying the A
> constructor several times to the same B or C value.  This can be done by
> memoization.  One can add an extra field to all the blocks described
> above, initialized to 0, and updated to point to the "next" application
> of A when requested.
>
> So, we would have:
>
>    c0 = 2:(id_t, 0, 0)
>
> When applying A to it, one create c1
>
>    c1 = 2:(id_t, c0, 0)
>
> and update the last field of c0 to be c1:
>
>    c0 = 2:(id_t, 0, c1)
>
> If one needs to apply A again to c0, one can reuse the existing value.
> The same applies to non-constant constructors as well.
>
>
>
> -- Alain
>


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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-24 10:16           ` Alain Frisch
@ 2014-01-24 13:32             ` Yaron Minsky
  0 siblings, 0 replies; 53+ messages in thread
From: Yaron Minsky @ 2014-01-24 13:32 UTC (permalink / raw)
  To: Alain Frisch
  Cc: Gabriel Scherer, Damien Guichard, Julien Blond, David House,
	Caml Mailing List

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

I really do think that if the engineering challenges can be overcome, this
would be a very useful representation to have on hand. There are many
situations where the only way to get a sufficiently light memory
representation is to use hand coded hacks that try to implement similar
schemes using the Obj module.  It wound be far better to have this as a
first class part of the language.
On Jan 24, 2014 5:16 AM, "Alain Frisch" <alain@frisch.fr> wrote:

> Revised description:  there is no need to keep the tag on B or C values
> when applying the A constructor, and one can skip the 0 integer as the
> second field when applying the B/C constructor.
>
>    B (x, y)   ---->   b0 = 1:(id_t,x, y)
> A (B (x, y))  ---->   b1 = 0:(id_t, b0)
>
>    C          ---->   c0 = 2:(id_t)
> A  C          ---->   c1 = 0:(id_t, c0)
>
>
> This simplifies the criterion for checking if a value of type t has the
> B/C constructor (tag = 1 or 2) or the A constructor (tag = 0, and the
> argument is the second field of the block if the first is id_t, and the
> value itself otherwise).
>
> -- Alain
>
>
> On 01/24/2014 11:06 AM, Alain Frisch wrote:
>
>> On 01/17/2014 10:10 AM, Gabriel Scherer wrote:
>>
>>> There have been recurrent discussions of optimizing `'a option` to
>>> avoid allocation in some cases, which is interesting when it is used
>>> as a default value for example. (The nice recent blog post by Thomas
>>> Leonard also seems to assume that `'a option` is somehow optimized.)
>>>
>>> My strictly personal opinion is that I doubt this would be a good
>>> idea, because I expect a fair share of the programming practice that
>>> currently use ('a option) to move to something like (('a,
>>> error-description) either) later in their lifetime, and I wouldn't
>>> want people to avoid to do that for performance concerns.
>>> Historically, we've rather come to see special-case representation
>>> optimizations (eg. array of floats) as a mistake -- but on the other
>>> hand there is not much downside to record of floats.
>>>
>>
>> It could be argued the role of option types is important enough to
>> justify a special treatment for them.  But maybe one could think (just
>> for the fun of it) about a more general optimized representation for sum
>> types where one constructor should behave (mostly) as the identity at
>> runtime.
>>
>> To take an example, consider a type:
>>
>>    type ('a, 'b) t =
>>       | A of 'a
>>       | B of 'b * 'b
>>       | C
>>
>> with some marker to tell the compiler to optimize the representation of A.
>>
>> If one wants the constructor A to be the identity at runtime (in most
>> cases), we still need to distinguish C from A C, A (A C), A (A (A C)),
>> etc,  and B (x, y) from A (B (x, y)), A (A (B (x, y))), etc.  Here is
>> one possible implementation:  let's allocate a fresh value to represent
>> the identity of the t type:
>>
>>    id_t = 0:(0)
>>
>> that is, a block of size 1, tag 0, with a single 0 field (equivalent to:
>> id_t = ref ()).  (This value would be generated by the compiler and
>> passed along in modules which re-export the type t.)
>>
>> The value (B (x, y)) would be represented as a block b0 = 1:(id_t, 0, x,
>> y)  (block with tag 1 and 4 fields).  Applying the A constructor to such
>> a block b0 would return a new block b1 = 1:(id_t, b0).  Applying again
>> the A constructor to b1 would return b2 = 1:(id_t, b1).
>>
>> Similarly, the value C would be represented as a block c0 = 2:(id_t, 0).
>>   Applying A to such a value would return a block c1 = 1:(id_t, c0), and
>> then c2 = 1:(id_t, c1).
>>
>> So, in general, applying the A constructor to a value x requires to
>> check if its argument is a block whose first field is equal to id_t, and
>> in this case, it returns a new block with the same tag and the two
>> fields id_t and x.  In other cases, the constructors simply returns its
>> argument.
>>
>> With this representation, it is not difficult to deconstruct the three
>> constructors.  For a value of type t:
>>
>>   - If the value is a block whose first field is equal to id_t and its
>> second field is 0, then the value comes from the B or C constructor
>> (according to the block tag) and the arguments can be found in the block.
>>
>>   - If the value is a block whose first first is equal to id_t and its
>> second field is not 0, then the value comes from the A constructor, and
>> the argument is the second field of the block.
>>
>>   - Otherwise, the value comes from the A constructor and its argument
>> is represented by the same value.
>>
>>
>> There is one correctness problem with this representation, though:
>> applying the A constructor to a float value cannot be the identity,
>> because of the specific representation for float arrays (which is
>> triggered by checking if the value is a float block).  This means we
>> must also have a special representation for A x, A (A x), etc, where x
>> is a float.  The scheme above extends naturally to support this
>> representation:  a0 = 0:(id_t, 0, x), a1 = 0:(id_t, a0), etc.
>>
>>
>> Another drawback is related to the use of the id_t block, which does not
>> work well with the generic marshaling, and requires extra plumbing to
>> make this value available where the type t can be constructed or
>> deconstructed.  It's possible to do better for a type with a "global
>> name".
>>
>>
>> In case of a constant constructor such as C, one can of course
>> pre-allocate the block c0 = 2:(id_t, 0).  To avoid passing an extra
>> value around, one could store it within id_t itself (id_t = 0:(c0)
>> instead of id_t = 0:(0)).
>>
>> Another optimization is to avoid the allocation when applying the A
>> constructor several times to the same B or C value.  This can be done by
>> memoization.  One can add an extra field to all the blocks described
>> above, initialized to 0, and updated to point to the "next" application
>> of A when requested.
>>
>> So, we would have:
>>
>>    c0 = 2:(id_t, 0, 0)
>>
>> When applying A to it, one create c1
>>
>>    c1 = 2:(id_t, c0, 0)
>>
>> and update the last field of c0 to be c1:
>>
>>    c0 = 2:(id_t, 0, c1)
>>
>> If one needs to apply A again to c0, one can reuse the existing value.
>> The same applies to non-constant constructors as well.
>>
>>
>>
>> -- Alain
>>
>>
>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>

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

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

* RE: [Caml-list] How much optimized is the 'a option type ?
  2014-01-24  8:34                         ` Andreas Rossberg
@ 2014-01-24 16:56                           ` Jon Harrop
  2014-01-27 15:29                             ` Goswin von Brederlow
  0 siblings, 1 reply; 53+ messages in thread
From: Jon Harrop @ 2014-01-24 16:56 UTC (permalink / raw)
  To: 'Andreas Rossberg'; +Cc: 'Ocaml Mailing List'

On 24.01.2014 08:34, Andreas Rossberg wrote:
> On Jan 24, 2014, at 09:22 , Jon Harrop <jon@ffconsultancy.com> wrote:
>> With value types you can almost completely avoid the garbage 
>> collector by replacing pointers with indices into an array of value 
>> types that acts as a pool allocator. This can be useful for avoiding 
>> GC latency and for optimizing for collections that violate the 
>> generational hypothesis (e.g.
>> long-lived Sets and Maps).
>
> As you well know, though, pervasive unboxing as for value types is 
> incompatible with a uniform representation approach like used by 
> OCaml. And non-uniform representation requires either static 
> monomorphisation (not possible in OCaml, because of first-class 
> polymorphism and separate compilation), or dynamic monomorphisation 
> (not possible without just-in-time compilation), or runtime type 
> passing and switching (expensive).

I think there are halfway houses as well...

Options could keep the same uniform representation when on the heap but be
unboxed when they are stored locally (arguments, local variables and return
values). You could either carry the pointer to the original option (if any)
or re-allocate when it was needed.

If run-time type passing and switching is expensive because of virtual
dispatch then you could replace the dynamic jump with a test to see if the
location is the same as it was for the last jump and, if so, use a static
jump and then update just the static jump using JIT compilation. 
That requires JIT compilation but, perhaps, so little JIT compilation that
the technique is of interest?

The required run-time type information could just be the number of
(uniformly-represented) words in each value and the "switch" could be a loop
(that usually does only one iteration). For example, the "A of 'a | B of 'b
* 'b | C" could be represented using 3 words per value instead of one: one
for the tag A=1|B=2|C=3 and two for the two potential arguments.

On a related note, doesn't OCaml box multiple return values as well? Could
it use sret form and elide the write barrier instead?

Even if such approaches don't improve overall performance they should shift
the burden off the GC and onto the generated code which would make it easier
to obtain good performance for alternative GC implementations (like OC4MC).

Cheers,
Jon.



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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-24  8:22                       ` Jon Harrop
  2014-01-24  8:34                         ` Andreas Rossberg
@ 2014-01-27 10:03                         ` Goswin von Brederlow
  1 sibling, 0 replies; 53+ messages in thread
From: Goswin von Brederlow @ 2014-01-27 10:03 UTC (permalink / raw)
  To: Jon Harrop; +Cc: 'Yotam Barnoy', 'Ocaml Mailing List'

On Fri, Jan 24, 2014 at 08:22:43AM -0000, Jon Harrop wrote:
> Yotam wrote:
> > Just to clarify, by value types you mean stuff allocated on the stack,
> right?
> 
> A value type is just an unboxed type like a C struct. A local variable of a
> value type is stored on the stack. A field inside a heap-allocated object
> that is a value type is stored inside the object and not in a separate
> object. An array of value types is a single contiguous block of memory with
> no pointers (e.g. an array of complex numbers).
> 
> With value types you can almost completely avoid the garbage collector by
> replacing pointers with indices into an array of value types that acts as a
> pool allocator. This can be useful for avoiding GC latency and for
> optimizing for collections that violate the generational hypothesis (e.g.
> long-lived Sets and Maps).
> 
> In HLVM, tuples were value types. For example, an (int * float) array is
> represented as a single contiguous block of memory. In constrast, OCaml
> represents this is an array of pointers to pairs where the second element is
> another pointer to a boxed float.
> 
> Value types and reified generics permit very efficient hash tables. For
> example, the Dictionary<int, float> type on .NET does not contain any
> pointers.
> 
> Cheers,
> Jon.

Problem is that a value is a fixed size and fits in a register. A
tuple does not. (int * float) even takes the space of 3 values on
32bit. You can unbox that in the optimizer for local use but in memory
and in function calls you need to pass this as box. Otherwise
polymorphic functions break.

Putting larger structures into an array without boxing also only works
for immutable objects and by copying them every time they are passed
around. You can't copy a mutable and you can't pass a pointer to the
middle of an array to another function or the GC might freak out.

So you have to be verry carefull where you use those unboxed arrays.
They only works within a single module like a Hashtbl.

MfG
	Goswin

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-24 16:56                           ` Jon Harrop
@ 2014-01-27 15:29                             ` Goswin von Brederlow
  2014-01-27 16:18                               ` Yotam Barnoy
  0 siblings, 1 reply; 53+ messages in thread
From: Goswin von Brederlow @ 2014-01-27 15:29 UTC (permalink / raw)
  To: caml-list

On Fri, Jan 24, 2014 at 04:56:46PM -0000, Jon Harrop wrote:
> On 24.01.2014 08:34, Andreas Rossberg wrote:
> > On Jan 24, 2014, at 09:22 , Jon Harrop <jon@ffconsultancy.com> wrote:
> >> With value types you can almost completely avoid the garbage 
> >> collector by replacing pointers with indices into an array of value 
> >> types that acts as a pool allocator. This can be useful for avoiding 
> >> GC latency and for optimizing for collections that violate the 
> >> generational hypothesis (e.g.
> >> long-lived Sets and Maps).
> >
> > As you well know, though, pervasive unboxing as for value types is 
> > incompatible with a uniform representation approach like used by 
> > OCaml. And non-uniform representation requires either static 
> > monomorphisation (not possible in OCaml, because of first-class 
> > polymorphism and separate compilation), or dynamic monomorphisation 
> > (not possible without just-in-time compilation), or runtime type 
> > passing and switching (expensive).
> 
> I think there are halfway houses as well...
> 
> Options could keep the same uniform representation when on the heap but be
> unboxed when they are stored locally (arguments, local variables and return
> values). You could either carry the pointer to the original option (if any)
> or re-allocate when it was needed.

They should certainly be unboxed when in registers. So

let t = (23, 42.0) in

would basically become

let t_0 = 23 in   (* r0 *)
let t_1 = 42.0 in (* fpu0 *)

Unless the tuple escapes the scope (either up or down) it should never
be allocated.

But you can't just put a float 42.0 on the heap or even stack when the
GC might get called. That needs to be boxed in some way to avoid it
getting misread as pointer.
 
> If run-time type passing and switching is expensive because of virtual
> dispatch then you could replace the dynamic jump with a test to see if the
> location is the same as it was for the last jump and, if so, use a static
> jump and then update just the static jump using JIT compilation. 
> That requires JIT compilation but, perhaps, so little JIT compilation that
> the technique is of interest?

Or compile code poly-monomorphic. Meaning for a function
taking/returning a tuple compile 2 (or more) flavours. One that
allocates the tuple and one that passes the tuple in registers.

Obviously higher level function would need a lot of flavours to cover
all combinations. And closure would need multiple flavours too. But
when there are too many cases, or when it is undecidable, the compiler
can simply use the base case of allocaating everything like it does
now. But all of this would be done static at compile time.
 
> The required run-time type information could just be the number of
> (uniformly-represented) words in each value and the "switch" could be a loop
> (that usually does only one iteration). For example, the "A of 'a | B of 'b
> * 'b | C" could be represented using 3 words per value instead of one: one
> for the tag A=1|B=2|C=3 and two for the two potential arguments.
> 
> On a related note, doesn't OCaml box multiple return values as well? Could
> it use sret form and elide the write barrier instead?

There are never multiple return values. You can only return tuples.

let f x y z = (x, y, z)
let (x,y,z) = f 1 2 3

It would be nice not to allocate that tuple. Does ocaml allocate it?
Or does inlining optimize the tuple away?

> Even if such approaches don't improve overall performance they should shift
> the burden off the GC and onto the generated code which would make it easier
> to obtain good performance for alternative GC implementations (like OC4MC).
> 
> Cheers,
> Jon.

MfG
	Goswin

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-27 15:29                             ` Goswin von Brederlow
@ 2014-01-27 16:18                               ` Yotam Barnoy
  2014-01-29  7:56                                 ` Goswin von Brederlow
                                                   ` (2 more replies)
  0 siblings, 3 replies; 53+ messages in thread
From: Yotam Barnoy @ 2014-01-27 16:18 UTC (permalink / raw)
  To: Goswin von Brederlow; +Cc: Ocaml Mailing List

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

>
> But you can't just put a float 42.0 on the heap or even stack when the
> GC might get called. That needs to be boxed in some way to avoid it
> getting misread as pointer.
>
>
It wouldn't be too hard to add a word of metadata to the stack to tell the
GC what's a pointer and what isn't. Haskell does this for function calls
(in fact, if the metadata doesn't fit in a word, it allocates a separate
metadata structure), and F# has this from the .NET runtime which has full
type metadata for everything.

Problem is that a value is a fixed size and fits in a register. A
> tuple does not. (int * float) even takes the space of 3 values on
> 32bit. You can unbox that in the optimizer for local use but in memory
> and in function calls you need to pass this as box. Otherwise
> polymorphic functions break.
>
> Putting larger structures into an array without boxing also only works
> for immutable objects and by copying them every time they are passed
> around. You can't copy a mutable and you can't pass a pointer to the
> middle of an array to another function or the GC might freak out.
>

Leaving it to the optimizer is problematic because it might cause a lot of
unneeded boxing and unboxing.
Haskell has the {- #UNPACK -} pragma to unbox types. You have to be really
careful in haskell with this, because you're also changing the evaluation
semantics to be strict. This makes for really ugly optimized haskell code,
but maybe we can do something similar (but not as ugly). F# inherits .NET's
struct types, which are similarly limited, but also useful. Of course, once
you unbox, all parametric polymorphism is lost, but because you have
control over it, you can decide where it's worthwhile.

An example of unpack usage in haskell:

data T = T {-# UNPACK #-} !(Int,Int)

which would be equivalent to something like
type t = (int * int) [@u]

Note that the whole tuple is unboxed.

In haskell, you can now do

f :: T -> Int
f (T(i1,i2)) = i1 + i2

and in ocaml you'd do

let f : t -> int = fun (i1,i2) = i1 + i2

Of course, this would require more metadata for the stack. For the heap,
you'd probably want to just use a new tag or the custom tag. For ocaml
you'd also probably have to stipulate that polymorphic marshalling cannot
be performed on this type, and neither can polymorphic comparison -- you'd
have to have specific marshalling/comparison functions, which aren't too
difficult to generate automatically.

-Yotam



>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>

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

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-27 16:18                               ` Yotam Barnoy
@ 2014-01-29  7:56                                 ` Goswin von Brederlow
  2014-01-29  8:32                                 ` Jon Harrop
  2014-02-01 15:40                                 ` Goswin von Brederlow
  2 siblings, 0 replies; 53+ messages in thread
From: Goswin von Brederlow @ 2014-01-29  7:56 UTC (permalink / raw)
  To: Yotam Barnoy; +Cc: Ocaml Mailing List

On Mon, Jan 27, 2014 at 11:18:23AM -0500, Yotam Barnoy wrote:
> >
> > But you can't just put a float 42.0 on the heap or even stack when the
> > GC might get called. That needs to be boxed in some way to avoid it
> > getting misread as pointer.
> >
> >
> It wouldn't be too hard to add a word of metadata to the stack to tell the
> GC what's a pointer and what isn't. Haskell does this for function calls
> (in fact, if the metadata doesn't fit in a word, it allocates a separate
> metadata structure), and F# has this from the .NET runtime which has full
> type metadata for everything.
> 
> Problem is that a value is a fixed size and fits in a register. A
> > tuple does not. (int * float) even takes the space of 3 values on
> > 32bit. You can unbox that in the optimizer for local use but in memory
> > and in function calls you need to pass this as box. Otherwise
> > polymorphic functions break.
> >
> > Putting larger structures into an array without boxing also only works
> > for immutable objects and by copying them every time they are passed
> > around. You can't copy a mutable and you can't pass a pointer to the
> > middle of an array to another function or the GC might freak out.
> >
> 
> Leaving it to the optimizer is problematic because it might cause a lot of
> unneeded boxing and unboxing.
> Haskell has the {- #UNPACK -} pragma to unbox types. You have to be really
> careful in haskell with this, because you're also changing the evaluation
> semantics to be strict. This makes for really ugly optimized haskell code,
> but maybe we can do something similar (but not as ugly). F# inherits .NET's
> struct types, which are similarly limited, but also useful. Of course, once
> you unbox, all parametric polymorphism is lost, but because you have
> control over it, you can decide where it's worthwhile.
> 
> An example of unpack usage in haskell:
> 
> data T = T {-# UNPACK #-} !(Int,Int)
> 
> which would be equivalent to something like
> type t = (int * int) [@u]
> 
> Note that the whole tuple is unboxed.
> 
> In haskell, you can now do
> 
> f :: T -> Int
> f (T(i1,i2)) = i1 + i2
> 
> and in ocaml you'd do
> 
> let f : t -> int = fun (i1,i2) = i1 + i2
> 
> Of course, this would require more metadata for the stack. For the heap,
> you'd probably want to just use a new tag or the custom tag. For ocaml
> you'd also probably have to stipulate that polymorphic marshalling cannot
> be performed on this type, and neither can polymorphic comparison -- you'd
> have to have specific marshalling/comparison functions, which aren't too
> difficult to generate automatically.
> 
> -Yotam

That would make it a new type, incompatible with the old one. So a
function expecting 'a wouldn't accept 'a [@u] and everything would be
fine (but not nice). And then you can define the semantic that types
like that are passed and returned in registers if small enough.

As for allocation. On the stack you would have one big block for all
local variables and put unboxed structures there. You couldn't put the
values on the heap. So if you return a unpacked type then it has to be
copied (implizit if it is passed in regs) on return or the caller has
to pass a pointer to where the result should go as implizit argument.

MfG
	Goswin

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

* RE: [Caml-list] How much optimized is the 'a option type ?
  2014-01-27 16:18                               ` Yotam Barnoy
  2014-01-29  7:56                                 ` Goswin von Brederlow
@ 2014-01-29  8:32                                 ` Jon Harrop
  2014-01-29 16:11                                   ` Yotam Barnoy
  2014-02-01 15:40                                 ` Goswin von Brederlow
  2 siblings, 1 reply; 53+ messages in thread
From: Jon Harrop @ 2014-01-29  8:32 UTC (permalink / raw)
  To: 'Yotam Barnoy', 'Goswin von Brederlow'
  Cc: 'Ocaml Mailing List'

Yotam wrote:
> Of course, once you unbox, all parametric polymorphism is lost

Is it?

You would have to box the tuple before passing it to a polymorphic function
with the type 'a -> 'a. However, if the function has the type 'a * 'b -> 'b
* 'a then you could always unbox, right?

Cheers,
Jon.



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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-29  8:32                                 ` Jon Harrop
@ 2014-01-29 16:11                                   ` Yotam Barnoy
  2014-01-30 18:43                                     ` Yotam Barnoy
  2014-01-30 21:31                                     ` Jon Harrop
  0 siblings, 2 replies; 53+ messages in thread
From: Yotam Barnoy @ 2014-01-29 16:11 UTC (permalink / raw)
  To: Jon Harrop; +Cc: Goswin von Brederlow, Ocaml Mailing List

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

On Wed, Jan 29, 2014 at 3:32 AM, Jon Harrop <jon@ffconsultancy.com> wrote:

> Yotam wrote:
> > Of course, once you unbox, all parametric polymorphism is lost
>
> Is it?
>
>
It is in haskell. In general, I don't think you can do any parametric
polymorphism without metadata.


> You would have to box the tuple before passing it to a polymorphic function
> with the type 'a -> 'a. However, if the function has the type 'a * 'b -> 'b
> * 'a then you could always unbox, right?
>
>
I don't think so. Without metadata, how do you know where one tuple member
ends and another begins?

Yotam

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

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-29 16:11                                   ` Yotam Barnoy
@ 2014-01-30 18:43                                     ` Yotam Barnoy
  2014-02-01 15:58                                       ` Goswin von Brederlow
  2014-01-30 21:31                                     ` Jon Harrop
  1 sibling, 1 reply; 53+ messages in thread
From: Yotam Barnoy @ 2014-01-30 18:43 UTC (permalink / raw)
  To: Jon Harrop; +Cc: Goswin von Brederlow, Ocaml Mailing List

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

BTW there's a compromise with unboxing that also has benefits, which is
embedding. An [@embed] annotation could turn an array into an embedding
array, for example. This would mean that an array would have boxed members
within it ie. not accessible via pointers. The advantages are better cache
performance and that the GC could be instructed when the array is
completely flat ie. an embedded array without any pointers could be skipped
by the GC in the mark phase. It would have full polymorphism capability.

The down side is that deallocating the array without deallocating the
embedded structure would be tricky. When deallocating, you have to check
every member to see if it should be deallocated as well. If not, you copy
the member (minor heap) or reallocate the member where it is in memory
(major heap).

Yotam


On Wed, Jan 29, 2014 at 11:11 AM, Yotam Barnoy <yotambarnoy@gmail.com>wrote:

>
> On Wed, Jan 29, 2014 at 3:32 AM, Jon Harrop <jon@ffconsultancy.com> wrote:
>
>> Yotam wrote:
>> > Of course, once you unbox, all parametric polymorphism is lost
>>
>> Is it?
>>
>>
> It is in haskell. In general, I don't think you can do any parametric
> polymorphism without metadata.
>
>
>> You would have to box the tuple before passing it to a polymorphic
>> function
>> with the type 'a -> 'a. However, if the function has the type 'a * 'b ->
>> 'b
>> * 'a then you could always unbox, right?
>>
>>
> I don't think so. Without metadata, how do you know where one tuple member
> ends and another begins?
>
> Yotam
>

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

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

* RE: [Caml-list] How much optimized is the 'a option type ?
  2014-01-29 16:11                                   ` Yotam Barnoy
  2014-01-30 18:43                                     ` Yotam Barnoy
@ 2014-01-30 21:31                                     ` Jon Harrop
  2014-01-30 21:43                                       ` Yotam Barnoy
  1 sibling, 1 reply; 53+ messages in thread
From: Jon Harrop @ 2014-01-30 21:31 UTC (permalink / raw)
  To: 'Yotam Barnoy'
  Cc: 'Goswin von Brederlow', 'Ocaml Mailing List'

Yotam wrote:
> I don't think so. Without metadata, how do you know where one tuple member
ends and another begins?

Use static type information. When the type is known to be 'a * 'b you use
the unboxed representation. Otherwise you default to the boxed
representation.

OCaml already does this to some extent because functions that accept a tuple
are compiled to multi-argument functions (IIRC). So this would just be an
extension to handle the return value too. The same idea could be used with
many other types, e.g. unboxed optional arguments.

Cheers,
Jon.



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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-30 21:31                                     ` Jon Harrop
@ 2014-01-30 21:43                                       ` Yotam Barnoy
  2014-01-31  8:26                                         ` Jon Harrop
  0 siblings, 1 reply; 53+ messages in thread
From: Yotam Barnoy @ 2014-01-30 21:43 UTC (permalink / raw)
  To: Jon Harrop; +Cc: Goswin von Brederlow, Ocaml Mailing List

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

I don't really understand how this could work. If the type of a function is
'a * 'b -> 'c then the function expects 2 tuple members, right? It has no
idea what their size is, because it can be called on any tuple. Now let's
say the tuple is float * int. If we unbox the tuple,  we get 3 words, with
the int comprising the 3rd word, and no metadata. How does the function
know how big each member is, or where to find each member? Are you assuming
we monomorphize the function?

Yotam


On Thu, Jan 30, 2014 at 4:31 PM, Jon Harrop <jon@ffconsultancy.com> wrote:

> Yotam wrote:
> > I don't think so. Without metadata, how do you know where one tuple
> member
> ends and another begins?
>
> Use static type information. When the type is known to be 'a * 'b you use
> the unboxed representation. Otherwise you default to the boxed
> representation.
>
> OCaml already does this to some extent because functions that accept a
> tuple
> are compiled to multi-argument functions (IIRC). So this would just be an
> extension to handle the return value too. The same idea could be used with
> many other types, e.g. unboxed optional arguments.
>
> Cheers,
> Jon.
>
>
>

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

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

* RE: [Caml-list] How much optimized is the 'a option type ?
  2014-01-30 21:43                                       ` Yotam Barnoy
@ 2014-01-31  8:26                                         ` Jon Harrop
  0 siblings, 0 replies; 53+ messages in thread
From: Jon Harrop @ 2014-01-31  8:26 UTC (permalink / raw)
  To: 'Yotam Barnoy'
  Cc: 'Goswin von Brederlow', 'Ocaml Mailing List'

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

 

I see. I meant unbox the tuple as in "the tuple and only the tuple" rather
than "the tuple and everything inside the tuple". So unboxing a float * int
would give you two words, one pointing to the boxed float and the other
containing a tagged int.

 

Cheers,

Jon.

 

From: Yotam Barnoy [mailto:yotambarnoy@gmail.com] 
Sent: 30 January 2014 21:43
To: Jon Harrop
Cc: Goswin von Brederlow; Ocaml Mailing List
Subject: Re: [Caml-list] How much optimized is the 'a option type ?

 

I don't really understand how this could work. If the type of a function is
'a * 'b -> 'c then the function expects 2 tuple members, right? It has no
idea what their size is, because it can be called on any tuple. Now let's
say the tuple is float * int. If we unbox the tuple,  we get 3 words, with
the int comprising the 3rd word, and no metadata. How does the function know
how big each member is, or where to find each member? Are you assuming we
monomorphize the function?

Yotam

 

On Thu, Jan 30, 2014 at 4:31 PM, Jon Harrop <jon@ffconsultancy.com> wrote:

Yotam wrote:
> I don't think so. Without metadata, how do you know where one tuple member
ends and another begins?

Use static type information. When the type is known to be 'a * 'b you use
the unboxed representation. Otherwise you default to the boxed
representation.

OCaml already does this to some extent because functions that accept a tuple
are compiled to multi-argument functions (IIRC). So this would just be an
extension to handle the return value too. The same idea could be used with
many other types, e.g. unboxed optional arguments.

Cheers,
Jon.



 


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

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-27 16:18                               ` Yotam Barnoy
  2014-01-29  7:56                                 ` Goswin von Brederlow
  2014-01-29  8:32                                 ` Jon Harrop
@ 2014-02-01 15:40                                 ` Goswin von Brederlow
  2 siblings, 0 replies; 53+ messages in thread
From: Goswin von Brederlow @ 2014-02-01 15:40 UTC (permalink / raw)
  To: Yotam Barnoy; +Cc: Ocaml Mailing List

On Mon, Jan 27, 2014 at 11:18:23AM -0500, Yotam Barnoy wrote:
> >
> > But you can't just put a float 42.0 on the heap or even stack when the
> > GC might get called. That needs to be boxed in some way to avoid it
> > getting misread as pointer.
> >
> >
> It wouldn't be too hard to add a word of metadata to the stack to tell the
> GC what's a pointer and what isn't. Haskell does this for function calls
> (in fact, if the metadata doesn't fit in a word, it allocates a separate
> metadata structure), and F# has this from the .NET runtime which has full
> type metadata for everything.

You can do that. It's called BOXING.

Even if you create just a single box for the whole stackframe of the
function it is still a box.

See the other thread about changing the in memory represenation of
ocaml for how to improve having boxed with mixed content so
int32/int64/float don't need extra boxing on their own.
 
> Problem is that a value is a fixed size and fits in a register. A
> > tuple does not. (int * float) even takes the space of 3 values on
> > 32bit. You can unbox that in the optimizer for local use but in memory
> > and in function calls you need to pass this as box. Otherwise
> > polymorphic functions break.
> >
> > Putting larger structures into an array without boxing also only works
> > for immutable objects and by copying them every time they are passed
> > around. You can't copy a mutable and you can't pass a pointer to the
> > middle of an array to another function or the GC might freak out.
> >
> 
> Leaving it to the optimizer is problematic because it might cause a lot of
> unneeded boxing and unboxing.
> Haskell has the {- #UNPACK -} pragma to unbox types. You have to be really
> careful in haskell with this, because you're also changing the evaluation
> semantics to be strict. This makes for really ugly optimized haskell code,
> but maybe we can do something similar (but not as ugly). F# inherits .NET's
> struct types, which are similarly limited, but also useful. Of course, once
> you unbox, all parametric polymorphism is lost, but because you have
> control over it, you can decide where it's worthwhile.
> 
> An example of unpack usage in haskell:
> 
> data T = T {-# UNPACK #-} !(Int,Int)
> 
> which would be equivalent to something like
> type t = (int * int) [@u]
> 
> Note that the whole tuple is unboxed.
> 
> In haskell, you can now do
> 
> f :: T -> Int
> f (T(i1,i2)) = i1 + i2
> 
> and in ocaml you'd do
> 
> let f : t -> int = fun (i1,i2) = i1 + i2
> 
> Of course, this would require more metadata for the stack. For the heap,
> you'd probably want to just use a new tag or the custom tag. For ocaml
> you'd also probably have to stipulate that polymorphic marshalling cannot
> be performed on this type, and neither can polymorphic comparison -- you'd
> have to have specific marshalling/comparison functions, which aren't too
> difficult to generate automatically.
> 
> -Yotam

Consider this:

type ['a] tt = ('a * 'a) [@u]
let ff : 'a tt -> ('a -> int) -> int = fun (t1, t2) f = f t2
let x = ff ((1, 2), (3, 4)) f

The ff function is tail recursive so f is called with the arguments of
ff no longer registered with the GC. And f is passed a pointer to the
middle of the tt type. Now lets assume the GC will run inside f.

*BOOM*

The tt type is no longer reachable so it would be freed. f has a
pointer pointing to the middle of a block causing the GC to parse the
t1 part of tt type as metadata.

Overall verry bad. Boxed and UNPACKed types would have to be
incompatible in ocaml.

MfG
	Goswin

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

* Re: [Caml-list] How much optimized is the 'a option type ?
  2014-01-30 18:43                                     ` Yotam Barnoy
@ 2014-02-01 15:58                                       ` Goswin von Brederlow
  0 siblings, 0 replies; 53+ messages in thread
From: Goswin von Brederlow @ 2014-02-01 15:58 UTC (permalink / raw)
  To: Yotam Barnoy; +Cc: Jon Harrop, Ocaml Mailing List

On Thu, Jan 30, 2014 at 01:43:59PM -0500, Yotam Barnoy wrote:
> BTW there's a compromise with unboxing that also has benefits, which is
> embedding. An [@embed] annotation could turn an array into an embedding
> array, for example. This would mean that an array would have boxed members
> within it ie. not accessible via pointers. The advantages are better cache
> performance and that the GC could be instructed when the array is
> completely flat ie. an embedded array without any pointers could be skipped
> by the GC in the mark phase. It would have full polymorphism capability.
> 
> The down side is that deallocating the array without deallocating the
> embedded structure would be tricky. When deallocating, you have to check
> every member to see if it should be deallocated as well. If not, you copy
> the member (minor heap) or reallocate the member where it is in memory
> (major heap).
> 
> Yotam

When deallocating the array you simply deallocate it all. You can't
have any pointers to inside the array floating around or the GC would
blow up. An array of embedded values can only be freed when nothing
has access to it any more at all. And access to members can only b
done as pointer to array + offset.

> On Wed, Jan 29, 2014 at 11:11 AM, Yotam Barnoy <yotambarnoy@gmail.com>wrote:
> 
> >
> > On Wed, Jan 29, 2014 at 3:32 AM, Jon Harrop <jon@ffconsultancy.com> wrote:
> >
> >> Yotam wrote:
> >> > Of course, once you unbox, all parametric polymorphism is lost
> >>
> >> Is it?
> >>
> >>
> > It is in haskell. In general, I don't think you can do any parametric
> > polymorphism without metadata.
> >
> >
> >> You would have to box the tuple before passing it to a polymorphic
> >> function
> >> with the type 'a -> 'a. However, if the function has the type 'a * 'b ->
> >> 'b
> >> * 'a then you could always unbox, right?

let f =
  let t = ref 0 in
  function (x, y) ->
    t := y;
    (y, x)

With f being unboxed you end up with a pointer to the middle of a
tuple in t and the GC goes *BOOM*.

Unboxed values allow only some operations.

> > I don't think so. Without metadata, how do you know where one tuple member
> > ends and another begins?
> >
> > Yotam

Being unboxed you get the first member in R0 and the second in R1.

MfG
	Goswin

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

end of thread, other threads:[~2014-02-01 15:58 UTC | newest]

Thread overview: 53+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-01-17  7:35 [Caml-list] How much optimized is the 'a option type ? Damien Guichard
2014-01-17  7:55 ` David House
2014-01-17  8:16   ` Julien Blond
2014-01-17  8:40     ` David House
2014-01-17  9:10       ` Gabriel Scherer
2014-01-17  9:22         ` Simon Cruanes
2014-01-17 17:57           ` Gerd Stolpmann
2014-01-18  1:35             ` Jon Harrop
2014-01-19  6:19               ` oleg
2014-01-21  1:51                 ` Francois Berenger
2014-01-18  1:01         ` Jon Harrop
2014-01-24 10:06         ` Alain Frisch
2014-01-24 10:16           ` Alain Frisch
2014-01-24 13:32             ` Yaron Minsky
     [not found]       ` <CAK=fH+jfi=GsMYBZzmuo=V5UAWimyxiiamY2+DkLg6F0i8XHGw@mail.gmail.com>
2014-01-17  9:11         ` David House
2014-01-17 11:23           ` Jonathan Kimmitt
2014-01-17 13:46             ` Nicolas Braud-Santoni
2014-01-17 13:56               ` Frédéric Bour
2014-01-17 14:02               ` Yaron Minsky
2014-01-17 14:09                 ` Simon Cruanes
2014-01-17 22:52                   ` Yaron Minsky
2014-01-18  1:37                   ` Jon Harrop
2014-01-17 14:24                 ` Gabriel Scherer
2014-01-17 22:29                   ` Yaron Minsky
2014-01-18  1:27                 ` Jon Harrop
2014-01-18  1:18             ` Jon Harrop
2014-01-20 10:16             ` Goswin von Brederlow
2014-01-20 11:23               ` Jonathan Kimmitt
2014-01-21  2:05                 ` Francois Berenger
2014-01-22 21:22                   ` Jon Harrop
2014-01-22 21:26               ` Jon Harrop
2014-01-23  9:29                 ` Goswin von Brederlow
2014-01-23 23:20                   ` Jon Harrop
2014-01-23 23:28                     ` Yotam Barnoy
2014-01-24  8:22                       ` Jon Harrop
2014-01-24  8:34                         ` Andreas Rossberg
2014-01-24 16:56                           ` Jon Harrop
2014-01-27 15:29                             ` Goswin von Brederlow
2014-01-27 16:18                               ` Yotam Barnoy
2014-01-29  7:56                                 ` Goswin von Brederlow
2014-01-29  8:32                                 ` Jon Harrop
2014-01-29 16:11                                   ` Yotam Barnoy
2014-01-30 18:43                                     ` Yotam Barnoy
2014-02-01 15:58                                       ` Goswin von Brederlow
2014-01-30 21:31                                     ` Jon Harrop
2014-01-30 21:43                                       ` Yotam Barnoy
2014-01-31  8:26                                         ` Jon Harrop
2014-02-01 15:40                                 ` Goswin von Brederlow
2014-01-27 10:03                         ` Goswin von Brederlow
2014-01-17 14:36 ` Markus Mottl
2014-01-17 15:49   ` Yotam Barnoy
2014-01-17 16:22     ` Markus Mottl
2014-01-20 10:09   ` Goswin von Brederlow

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