From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Stefan Monnier Newsgroups: gmane.emacs.devel Subject: Re: continuation passing in Emacs vs. JUST-THIS-ONE Date: Sun, 02 Apr 2023 22:09:38 -0400 Message-ID: References: <627090382.312345.1678539189382@office.mailbox.org> <87sfe7suog.fsf@gmail.com> <1c6fedae-10b4-5d97-5036-eaa736e1b816@gmail.com> <87mt4c6xju.fsf@logand.com> <87a6001xm0.fsf@logand.com> <87tty78fwg.fsf@logand.com> <875yad240l.fsf@logand.com> Mime-Version: 1.0 Content-Type: text/plain Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="36607"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Cc: Jim Porter , Karthik Chikmagalur , Thomas Koch , "emacs-devel@gnu.org" To: Tomas Hlavaty Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Mon Apr 03 04:10:41 2023 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pj9ea-0009JF-Rc for ged-emacs-devel@m.gmane-mx.org; Mon, 03 Apr 2023 04:10:41 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pj9dk-0006ah-4w; Sun, 02 Apr 2023 22:09:48 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pj9dh-0006We-Oo for emacs-devel@gnu.org; Sun, 02 Apr 2023 22:09:45 -0400 Original-Received: from mailscanner.iro.umontreal.ca ([132.204.25.50]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pj9df-0007g8-Ma for emacs-devel@gnu.org; Sun, 02 Apr 2023 22:09:45 -0400 Original-Received: from pmg2.iro.umontreal.ca (localhost.localdomain [127.0.0.1]) by pmg2.iro.umontreal.ca (Proxmox) with ESMTP id B439C80781; Sun, 2 Apr 2023 22:09:41 -0400 (EDT) Original-Received: from mail01.iro.umontreal.ca (unknown [172.31.2.1]) by pmg2.iro.umontreal.ca (Proxmox) with ESMTP id 542A68051D; Sun, 2 Apr 2023 22:09:40 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=iro.umontreal.ca; s=mail; t=1680487780; bh=24U2GtA85nkKB7Hoo9/44aBOra66Pz5uyaBEwA6JK1E=; h=From:To:Cc:Subject:In-Reply-To:References:Date:From; b=XEBKVEGQHJD/MkLK4naFOMU3WkTM5VY6OuHwgGvtSuisEWho63dSfa97Y6tN7m7gp Z6iwd8MllaSRqsIMnFyObeipXALMLOEA8uz92CIIc+Uxu4JM1hopKn/mSLCsJKFC6Q qvnOvyZy3vhNV4nJ8RtTOhUG8NvgNgBZ2VOZDmzGDGwY4K9AxXcYrMTjXYKiJvkP4a BRpAo0+1NID3slo3dor0oisRVJsrrJ/8K0OWeSvVlC3s/4sPZIT658qe+7wrVT2M0G UuYSweOo4qeraZv4ajijzExA9tN7E0kLRkDfRHiFF1RzvuHjL10yrqKMJcIjMFgJjg 5xAUKToODOsbA== Original-Received: from pastel (unknown [45.72.217.176]) by mail01.iro.umontreal.ca (Postfix) with ESMTPSA id EF1FD123353; Sun, 2 Apr 2023 22:09:39 -0400 (EDT) In-Reply-To: <875yad240l.fsf@logand.com> (Tomas Hlavaty's message of "Mon, 03 Apr 2023 02:39:06 +0200") Received-SPF: pass client-ip=132.204.25.50; envelope-from=monnier@iro.umontreal.ca; helo=mailscanner.iro.umontreal.ca X-Spam_score_int: -42 X-Spam_score: -4.3 X-Spam_bar: ---- X-Spam_report: (-4.3 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.devel:305055 Archived-At: > (defun await (future) > (let (z) > (while (eq 'EAGAIN (setq z (funcall future))) > (accept-process-output) > (sit-for 0.2)) > z)) So `await` blocks Emacs. IOW, your `await` is completely different from Javascript's `await`. > (defun promise-pipelining-server3 (req) > (funcall > (byte-compile-sexp > (let (f v z) > (dolist (x req) > (if (atom x) > (push x z) > (cl-destructuring-bind (k op l r) x > (let ((ll (if (symbolp l) > l > (let ((lk (gensym))) > (push `(,lk (slowly-thread ,l)) f) > `(await ,lk)))) > (rr (if (symbolp r) > r > (let ((rk (gensym))) > (push `(,rk (slowly-thread ,r)) f) > `(await ,rk))))) > (push `(,k (,op ,ll ,rr)) v))))) > `(lambda () > (let ,(nreverse f) > (let* ,(nreverse v) > (list ,@(nreverse z))))))))) And the use `await` above means that your Emacs will block while waiting for one result. `futur-let*` instead lets you compose async operations without blocking Emacs, and thus works more like Javascript's `await`. >> This blocks, so it's the equivalent of `futur-wait`. >> I.e. it's the thing we'd ideally never use. > I think that futur-wait (or wrapper future-get) aka await is essential > but what futur.el provides is not sufficient. There need to be > different await ways depending on use-case (process, thread, iter). Not sure what you mean by that. `futur-wait` does work in different ways depending on whether it's waiting for a process, a thread, etc: it's a generic function. The `iter` case (same for streams) is similar to process filters in that it doesn't map directly to "futures". So we'll probably want to supplement futures with "streams of futures" or something like that to try and provide a convenient interface for generators, streams, process filters and such. > await is necessary for waiting at top-level in any case. That's what `futur-wait` is for, indeed. > For top-level waiting in background, use await-in-background instead. `future-let*` seems to provide a better alternative that doesn't need to use a busy-loop polling from a timer. > Calling await immediately after async is useless (simply use blocking > call). The point of future is to make the distance between those calls > as big as possible so that the sum of times in the sequential case is > replaced with max of times in the parallel case. You're looking for parallelism. I'm not. I'm trying to provide a more convenient interface for async programming, e.g. when you need to consult a separate executable/server from within `jit-lock`, so you need to immediately reply to `jit-lock` saying "pretend it's already highlighted" spawn some async operation to query the external tool for info, and run some ELisp when the info comes back (which may require running some other external tool, after which you need to run some more ELisp, ...). > I think it is quite different. What is the point of futur-deliver, > futur-fail, futur-pure, futur--bind, futur--join, futur-let*, > futur-multi-bind when the lisp can figure those automatically? When writing the code by hand, for the cases targeted by my library, you *have* to use process sentinels. `futur.el` just provides a fairly thin layer on top. Lisp can't just "figure those out" for you. > Other use-cases would do something different, but once the future is > computed, it does not change so there is no state to maintain between > changes of the future. I'm not talking about saving some state in the future's value. I'm talking about saving some state in the "continuations/callbacks" created by `futur-let*` so that when you're called back you don't need to first manually re-establish your context. > One more thing: Is futur-abort a good idea? I don't know. I can see places where it might make sense to use it, but I don't know yet whether those places will actually be able to use it, whether it will work well, ... Stefan