emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: continuation passing in Emacs vs. JUST-THIS-ONE


From: Stefan Monnier
Subject: Re: continuation passing in Emacs vs. JUST-THIS-ONE
Date: Sun, 02 Apr 2023 22:09:38 -0400
User-agent: Gnus/5.13 (Gnus v5.13)

> (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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]