latch

Homepage: https://github.com/skeeto/elisp-latch

Updated:

Summary

Promises and latches for Elisp

Commentary

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.

Dependencies