This library provides a set of “Cell” for Elisp programming. A “Cell” is a container of single Lisp value, with extra information attached on it.
Currently there are 3 kinds of “Cell” in cell.el
A Some Cell add the “existence” information for a lisp value.
Some Cell can be united with nil
value to present a nullable value.
When writing funtion to query a collection. You can use
nil
to present “Not found” and Some(x) to present your found value.
When using nil
to present “Not fonud” in tranditional Lisp programming
style. The caller of your query function may hard to differentiate
these two status: “Found and get a nil
value” and “Not found”.
(defun clear-plist-get (plist key)
(pcase (plist-member plist key)
(`(,_k ,v)
(cell-some v))
(_
nil)))
(let ((plist '(:key nil)))
(plist-get plist :key) ;=> nil
(plist-get plist :val) ;=> nil
(clear-plist-get plist :key) ;=> Some(nil)
(clear-plist-get plist :val) ;=> nil
)
cell.el
also provides some facility to operates on a Some(x) | nil union.
(let ((some (cell-some 1))
(none nil))
(cell-option-map some #'1+) ;=> Some(2)
(cell-option-map none #'1+) ;=> nil
(pcase some
((cell-some inner)
(message "Some(%d)" inner))
(_ (error "Unreachable!"))))
A Box Cell is like a single-element vector, normally used as minimal mutable storage.
(let* ((box (cell-box "Emacs"))
(lst (list box))
(vec (vector box)))
(cl-assert (eq (cell-box-inner (nth 0 lst))
(cell-box-inner (aref vec 0))))
(setf (cell-box-inner (nth 0 lst)) "emacs")
(cl-assert (eq (cell-box-inner (nth 0 lst))
(cell-box-inner (aref vec 0)))))
A Weak Cell is like weak pointer in other languages. The reference in Weak Cell will not be considered in GC. This can help you manage struct with cyclic reference.
When design a RAII style API in Emacs Lisp, Weak Cell can help you differentiate “first class” reference and “second class” reference. And make sure finalizer can be run as expected.
(let ((weakptr (cell-weak (list 1 2 3 4))))
(cl-assert (equal (cell-weak-get weakptr)
(cell-option-some (list 1 2 3 4))))
(garbage-collect)
;; value inside weakptr was GCed because nothing other than a weak cell
;; held its reference. So `cell-weak-get' will return a None.
(cl-assert (equal (cell-weak-get weakptr)
(cell-option-none))))