Homepage: https://github.com/skeeto/elisp-latch
Updated:
Promises and latches for Elisp
This code (ab)uses `accept-process-output' and processes to provide
asynchronous blocking, allowing other functions to run before the
current execution context completes. All blocking will freeze the
Emacs display, but timers and I/O will continue to run.
Three classes are provided, each building on the last: latch,
one-time-latch, and promise. See `make-latch',
`make-one-time-latch', and `make-promise'.
Each latch has an associated process, which doesn't get garbage
collected, so they need to be destroyed when no longer in
use. One-time-latches destroy themselves automatically after one
use. Use `destroy-all-latches' to clean up during debugging.
Methods:
(`wait' latch &optional timeout)
Blocking wait on a latch for a `notify'.
(`notify' latch &optional value)
Resume all executation contexts waiting on the latch.
(`destroy' latch)
Free resources consumed by the latch.
(`deliver' promise value)
Deliver a value to a promise. Only happens once per promise.
(`retrieve' promise)
Retrieve a value from a promise, blocking if necessary.
A promise is basically a one-time-latch whose result can be
retrieved more than once (i.e. cached).
For example, to implement your own `sleep-for' function.
(defun my-sleep-for (n)
(let ((latch (make-one-time-latch)))
(run-at-time n nil #'notify latch t)
(wait latch)))
Or turn an asynchronous function (requires a callback to receive
the result) into a synchronous one (returns the result). Note the
important use of `lexical-let'!
(lexical-let ((latch (make-one-time-latch)))
(skewer-eval "Math.pow(3.1, 2.1)" (apply-partially #'notify latch))
(wait latch))
The same thing using a promise,
(lexical-let ((promise (make-promise)))
(skewer-eval "Math.pow(3.1, 2.1)" (apply-partially #'deliver promise))
(retrieve promise))
Futures:
A `future' macro is provided for educational purposes, but it is
completely useless in Emacs' single-threaded environment. Don't use
it.
Notice:
Due to a segfault bug (Debian #698096) in Emacs 24.2, this code
uses heavier PTY connections instead of pipes.