Mailing list for all users of the OCaml language and system.
 help / color / mirror / Atom feed
From: "Nicolás Ojeda Bär" <nicolas.ojeda.bar@lexifi.com>
To: "Matej Košík" <mail@matej-kosik.net>
Cc: OCaml Mailing List <caml-list@inria.fr>
Subject: Re: [Caml-list] stdlib → Queue → iter : implementation question / (possibly) bikeshedding
Date: Fri, 22 Dec 2017 12:55:52 +0100	[thread overview]
Message-ID: <CADK7aFPmJpRN16MiojL6v+v66DL=O=UV8KKGdQ_c2P+PM485cA@mail.gmail.com> (raw)
In-Reply-To: <64f1e880-fb8c-4432-3597-3485ec06c046@matej-kosik.net>

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

Dear Matej,

The reason is efficiency: absent any special optimizations, functions with
free variables need to allocate a closure for their values in order to be
able to find them when needed.
On top of the allocation of the closure, any access to a free variable will
have to go through the closure adding the cost of an extra indirection.

No such penalties are paid in the absence of free variables.

You can see this quite clearly in a simple example if you inspect the C--
intermediate language: if foo.ml contains

  let f x y =
    let g u = x + u in
    g y

then g is allocated a closure due to its free variable x and ocamlopt -dcmm
-inline 0 -c foo.ml shows

  (function{foo.ml:1,6-40} camlFoo__f_1328 (x/1329: val y/1330: val)
   (let
     g/1331 (alloc block-hdr(3319){foo.ml:2,8-17} "camlFoo__g_1331" 3
x/1329)
     (app{foo.ml:3,2-5} "camlFoo__g_1331" y/1330 g/1331 val)))

  (function{foo.ml:2,8-17} camlFoo__g_1331 (u/1332: val env/1337: val)
   (+ (+ (load val (+a env/1337 16)) u/1332) -1))

where you can see the allocation of the closure for g with (alloc
block-hdr(3319) ...) and the extra indirection to access x in this closure
with (load val (+ env 16))).

On the other hand, if we pass x explicitly, as in

  let f x y =
    let g x u = x + u in
    g x y

then no closure required and ocamlopt -dcmm -inline 0 foo.ml shows

  (function{foo.ml:1,6-44} camlFoo__f_1328 (x/1329: val y/1330: val)
   (let g/1331 "camlFoo__3" (+ (+ x/1329 y/1330) -1)))

  (function{foo.ml:2,8-19} camlFoo__g_1331 (x/1332: val u/1333: val)
   (+ (+ x/1332 u/1333) -1))

where you can see that no closure is allocated and no indirection is needed
to access x.

Best wishes,
Nicolás



On Fri, Dec 22, 2017 at 12:05 PM, Matej Košík <mail@matej-kosik.net> wrote:

> Hi,
>
> I just had a look at Queue.iter function as it is implemented by Ocaml
> standard library.
>
> The original version
>
>   (* https://github.com/ocaml/ocaml/blob/c08532f561548f6164278ba0d156da
> 841aefe44a/stdlib/queue.ml#L100-L108 *)
>
>   let iter =
>     let rec iter f cell =
>       match cell with
>       | Nil -> ()
>       | Cons { content; next } ->
>         f content;
>         iter f next
>     in
>   fun f q -> iter f q.first
>
> I am wondering about two things.
>
> ------------------------------------------------------------
> --------------------
>
> (1)
>
> Why is the original implementation preferred over
>
>   let iter f =
>     let rec iter cell =
>       match cell with
>       | Nil -> ()
>       | Cons { content; next } ->
>         f content;
>         iter next
>     in
>     fun q -> iter q.first
>
> where "f" would be bound once and then reused as many times as necessary
> (instead of passed over and over again within the inner "iter" loop).
>
> ------------------------------------------------------------
> --------------------
>
> (2)
>
> Why is the original implementation preferred over the following version
>
>   let iter f q =
>     let rec iter cell =
>       match cell with
>       | Nil -> ()
>       | Cons { content; next } ->
>         f content;
>         iter next
>     in
>     iter q.first
>
> ?
>
> Similar decisions where made elsewhere in stdlib so I am wondering what am
> I missing?
>
>

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

      reply	other threads:[~2017-12-22 11:56 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-12-22 11:05 Matej Košík
2017-12-22 11:55 ` Nicolás Ojeda Bär [this message]

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to='CADK7aFPmJpRN16MiojL6v+v66DL=O=UV8KKGdQ_c2P+PM485cA@mail.gmail.com' \
    --to=nicolas.ojeda.bar@lexifi.com \
    --cc=caml-list@inria.fr \
    --cc=mail@matej-kosik.net \
    /path/to/YOUR_REPLY

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

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