From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Authentication-Results: plum.tunbury.org; dkim=pass (1024-bit key; unprotected) header.d=inria.fr header.i=@inria.fr header.a=rsa-sha256 header.s=dc header.b=LVw+uc0v; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=okmij.org header.i=@okmij.org header.a=rsa-sha256 header.s=pair-202411190653 header.b=DZtHK1Am; dkim-atps=neutral Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=192.134.164.83; helo=mail2-relais-roc.national.inria.fr; envelope-from=caml-list-owner@inria.fr; receiver=tunbury.org Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by plum.tunbury.org (Postfix) with ESMTPS id 15EA4400A0 for ; Thu, 27 Feb 2025 12:00:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=inria.fr; s=dc; h=date:from:to:message-id:mime-version:subject:reply-to: sender:list-id:list-help:list-subscribe:list-unsubscribe: list-post:list-owner:list-archive; bh=J3hGOGXD0d4DFHNZM7vIpSngizD3nevZDFXbrRw91FU=; b=LVw+uc0vQUZRDN+yrvaAEmMyGFIKCGFfLYotoZyCC4YtKp6JGmSRGqIo IzO36flRzGZwSBdAT+pj1Tk0b7fUf324tn4dzu9WOxygOQvWl+Rd+DIJj 4h6LJGrWe9Y7g/HjgcyfhM6sC5GSoRfDt4Nh6Yuch0byP2vF6H0kNWF0U 0=; Received-SPF: Pass (mail2-relais-roc.national.inria.fr: domain of caml-list-owner@inria.fr designates 128.93.162.160 as permitted sender) identity=mailfrom; client-ip=128.93.162.160; receiver=mail2-relais-roc.national.inria.fr; envelope-from="caml-list-owner@inria.fr"; x-sender="caml-list-owner@inria.fr"; x-conformance=spf_only; x-record-type="v=spf1"; x-record-text="v=spf1 include:mailout.safebrands.com a:basic-mail.safebrands.com a:basic-mail01.safebrands.com a:basic-mail02.safebrands.com ip4:128.93.142.0/24 ip4:192.134.164.0/24 ip4:128.93.162.160 ip4:128.93.162.3 ip4:128.93.162.88 ip4:89.107.174.7 mx ~all" Received-SPF: None (mail2-relais-roc.national.inria.fr: no sender authenticity information available from domain of postmaster@sympa.inria.fr) identity=helo; client-ip=128.93.162.160; receiver=mail2-relais-roc.national.inria.fr; envelope-from="caml-list-owner@inria.fr"; x-sender="postmaster@sympa.inria.fr"; x-conformance=spf_only Authentication-Results: mail2-relais-roc.national.inria.fr; spf=Pass smtp.mailfrom=caml-list-owner@inria.fr; spf=None smtp.helo=postmaster@sympa.inria.fr; dkim=hardfail (signature did not verify [final]) header.i=@okmij.org X-IronPort-AV: E=Sophos;i="6.13,319,1732575600"; d="scan'208";a="210350165" Received: from prod-listesu18.inria.fr (HELO sympa.inria.fr) ([128.93.162.160]) by mail2-relais-roc.national.inria.fr with ESMTP; 27 Feb 2025 13:00:24 +0100 Received: by sympa.inria.fr (Postfix, from userid 20132) id C320FE0D27; Thu, 27 Feb 2025 13:00:23 +0100 (CET) Received: from mail3-relais-sop.national.inria.fr (mail3-relais-sop.national.inria.fr [192.134.164.104]) by sympa.inria.fr (Postfix) with ESMTPS id 25DD8E0260 for ; Thu, 27 Feb 2025 13:00:22 +0100 (CET) IronPort-SDR: 67c053d4_pWoGZasQhjYls5GTIeTvL1tVPWcD9bNSlFij70fUWBFmDTC fr7gcIgNxghiz5W/mgR5G5N+jkMBA0Fg9hUNwkA== X-IPAS-Result: =?us-ascii?q?A0HRAQAWU8BnjnIDJ0JagQmEF4FXMwcISI1SiFcdkUqOS?= =?us-ascii?q?w8BAwENQgIEAQEDAQOBTI5IAh8GAQQ0EwECBAEBAQEDAgMBAQEBAQEQAQEFA?= =?us-ascii?q?QEBAgEBAgQGAQIQAQEBAQEBOQVJhXsNgls7ghYsMIEIEwYBAThwg2GCZQIBs?= =?us-ascii?q?BWBATOBAYIMAQEG3gUJgUiFbIJjAYsJDg2BSEWJGIZsgjOFLIleiFqVfoFNH?= =?us-ascii?q?ANZLAFVExcLBwVhgRADgQ+BRnqCRWlJOgINAjWCHnyCK4RUhEOEQYVSghGGS?= =?us-ascii?q?wKEcIQvHUADC209NxQbolKENiZWXIEBgWKSP5JOoE08hCWBb4IQiAyVVzOHJ?= =?us-ascii?q?KMymH2jVCYPhSiBfiOBXE0wCIMiTwMZD446iHTFQzQ1PAIHCwEBAwmFRYokM?= =?us-ascii?q?4FLAQE?= IronPort-PHdr: A9a23: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 IjU0ZXt379iyPUyDgUcPWE= IronPort-Data: A9a23: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 aMJqayoja11pYMd0SqtRpKNJCwkgQ== IronPort-HdrOrdr: A9a23:obnidq3ZL+XEOB3ppOP1ZgqjBIgkLtp133Aq2lEZdPVwSL38qy nOpoV46faQskd0ZJhOo7290cW7LU80lqQFgrU5Gb+jWU3Ivm6sKp9/9M/exVTbexEWlNQ96U 4IScEXY7fN5DNB4/oSjjPWLz5NreP3l5yVuQ== X-Talos-CUID: 9a23:FEbrPW38snD9Qu23tH3HLLxfHuw1UCL56GvrPkbnNlQ2duKzTnmJwfYx X-Talos-MUID: =?us-ascii?q?9a23=3A53vI0A7Dxy2I1bZ+fzEgTJMmxoxH5aaHKUMmraw?= =?us-ascii?q?BnNWgC3Z/JhqHpQ24F9o=3D?= X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.13,319,1732575600"; d="scan'208";a="110208682" X-MGA-submission: =?us-ascii?q?MDHzw/X4fvlZdm3EpM500otGWNOCCwftJgiJ87?= =?us-ascii?q?ZV1+dKUbTV1q+U8YMl0gJOAxaoerYtuIpwzF5ipv4AN3QP9cb19Ecmte?= =?us-ascii?q?+DoKj6KeOzqJEsD3ZfnWz+n26QlY7RpxdBUwemz0njR2GVkm/hgB1siq?= =?us-ascii?q?ttNj0WYz1u79eCkxmzpSZnNg=3D=3D?= Received: from mail1.g3.pair.com ([66.39.3.114]) by mail3-smtp-sop.national.inria.fr with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Feb 2025 13:00:19 +0100 Received: from mail1.g3.pair.com (localhost [127.0.0.1]) by mail1.g3.pair.com (Postfix) with ESMTP id E74703FBB11; Thu, 27 Feb 2025 07:00:16 -0500 (EST) Received: from Magus.localnet (180.167.214.202.rev.vmobile.jp [202.214.167.180]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mail1.g3.pair.com (Postfix) with ESMTPSA id EF448582C55; Thu, 27 Feb 2025 07:00:15 -0500 (EST) Date: Thu, 27 Feb 2025 20:59:28 +0900 From: Oleg To: caml-list@inria.fr Message-ID: Mail-Followup-To: Oleg , caml-list@inria.fr MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=okmij.org; h=date:from:to:subject:message-id:mime-version:content-type; s=pair-202411190653; bh=J3hGOGXD0d4DFHNZM7vIpSngizD3nevZDFXbrRw91FU=; b=DZtHK1AmHbe1ISeretZHEnXDWvclbnVb+yGFLaiqa00pMx0ct9wTl7JeTVMlngPkxzOe/u21G/+HII90kJ95gIvDFhAoo+A3YFtKv9dxgjh4Gce9UCwf/gXtuNVl/BOKieiAoDjRvsMxSJMmqOiVhd/mwwWorcZFExCcPxoaV3wfR7aGtGtMO6YhRlpouMnw6JWSlUyYpCFWbDveTDCvQ+t8BwnzDha3ppM2g3n94YB5e/WNrgr2795iRtq3/KmqrHVFCBTzpl15rd/W2viq6DA7tYJFFaEJS8d76UI+DQZUFMT+fIfJZY+P9J1XkCUrR/ZgzzSqASH1fblScUnszw== X-Scanned-By: mailmunge 3.11 on 66.39.3.114 Subject: [Caml-list] do-while loops have always been in OCaml Reply-To: Oleg X-Loop: caml-list@inria.fr X-Sequence: 19276 Errors-To: caml-list-owner@inria.fr Precedence: list Precedence: bulk Sender: caml-list-request@inria.fr X-no-archive: yes List-Id: List-Help: List-Subscribe: List-Unsubscribe: List-Post: List-Owner: List-Archive: Archived-At: Whereas OCaml has `for' and `while' loops, C and Java-like languages also have `do-while'; the Pascal family has the closely-related `repeat-until' loops. There are cases (reminded below) where do-while comes in quite naturally, and with performance advantages. For quite a while I've been wishing for do-while~-- as is, without any performance-degrading emulation or extra booleans. Until I suddenly realized that do-while has always been in OCaml. Most likely this is well-known to many~-- but probably not to everyone. This message is meant to be a reminder and a reference, of how do-while, *with the expected performance*, is represented in OCaml. As a bit of motivation, the real need for (performant) do-while came in the development of the recent version of strymonas: the stream library with the utmost performance. Beside OCaml, strymonas also generates C code, which has do-while natively. I wanted an interface that supports do-while and produces the best code for both languages. The method in this article has been used in strymonas and indeed gave the desired performance -- matching, or surpassing in some cases, hand-written stream-processing code. The most common use case for do-while is executing some bit of (imperative, IO) code that turns out needing re-execution. The typical example is menu-selection. Here is how it looks in C: int c; do { puts("\nPlease enter"); puts("1. choice A"); puts("2. choice B"); puts("q. exit"); switch (c = getchar()) { case '1': puts("\n*** doing A"); break; case '2': puts("\n*** doing B"); break; } } while (!(c=='q' || c == EOF)); The menu has to be displayed first. It is re-displayed if an invalid choice is entered, and also to request another choice. In strymonas, a typical case for do-while is zipping of complex (nested, filtered, etc.) streams. At some point we execute the generator of one stream, which is to produce an item and let the further code deal with it. If the generator for some reason has not produced an item (e.g., because of the filtering) and has not set the termination trigger, it needs to be re-executed before we turn to the other stream. As well known, the lack of do-while loop does not limit expressiveness: After all, according to the Structured Programming theorem, every control flow may be converted to the one using sequential composition, branching and while-iteration~-- provided one may introduce an arbitrary amount of auxiliary (often boolean) state. For our running example, the menu-selection C code can be written in OCaml as follows: let again = ref true in while !again do print_endline "\nPlease enter"; print_endline "1. choice A"; print_endline "2. choice B"; print_endline "q. exit"; match input_char stdin with | exception End_of_file -> again := false | '1' -> print_endline "\n*** doing A" | '2' -> print_endline "\n*** doing B" | 'q' -> again := false | _ -> () done We have to introduce an extra boolean, and test for it, even before the first iteration where we know its value for sure. If we look at the generated code, we see two branches: one at the beginning, after the test for `again', and one, unconditionally, at the end, to be beginning of the loop. It seems insignificant~-- but not when it is repeated literally hundreds of millions of times in inner loops. The lack of do-while indeed hinders the performance, as I have confirmed in strymonas benchmarks. It turns out, however, that OCaml does have do-while. The menu-selection can be written to perfectly match the control flow of the original C code, also avoiding auxiliary booleans. In fact, we can avoid introducing any mutable state: while print_endline "\nPlease enter"; print_endline "1. choice A"; print_endline "2. choice B"; print_endline "q. exit"; match input_char stdin with | exception End_of_file -> false | '1' -> print_endline "\n*** doing A"; true | '2' -> print_endline "\n*** doing B"; true | 'q' -> false | _ -> true do () done That is the trick. To write it schematically, the do-while of C do stm while(test) is perfectly represented in OCaml as while stm; test do () done The compiled code (assembly) is exactly as desired, with no extra branches.