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.