Programmatically Setting Lisp Docstrings
I just updated my Elisp memoization function so
that it’s no longer a dirty hack. To work around the lack of closures,
due to the lack of lexical scope in Elisp, the original version used
uninterned symbols to store the look-up table. The new version in the
lexical-let, which does the same thing internally to fake
a closure. The new version in my dotfiles
repository uses the brand new
Emacs 24 lexical scoping.
It was “dirty” because it built a lambda function out of a list at run
time, taking advantage of the way Elisp currently handles
functions. The reason for this was that I wanted to inject the
original documentation string into the new function which can’t
normally be done when
lambda is used the correct way. When I updated
the function I fixed this as well. It uses a trick provided by Elisp,
which is different than the Common Lisp way that I assumed.
Both Elisp and Common Lisp have a
documentation function for
programmatically accessing symbol documentation. The Elisp version
only provides function documentation, so it only accepts one
(defun foo () "Foo." nil) (documentation 'foo) => "Foo."
The Common Lisp version must be told what type of documentation to
return, such as
(documentation 'foo 'function) => "Foo."
As it might be expected, this is
setf-able! It’s possible to update
or modify documentation strings without needing to redefine the
(setf (documentation 'foo 'function) "New doc string.")
Unfortunately it’s not
setf-able in Elisp. Instead you can set the
function-documentation property of the symbol. The
function will prefer this over the string stored in the function
(put 'foo 'function-documentation "Foo updated.") (documentation 'foo) => "Foo updated."
The downside is that this is a second place to put docstrings, leading to surprising behavior for developers unaware of this hack.
(put 'foo 'function-documentation "Old docstring.") (defun foo () "New docstring." nil) (documentation 'foo) => "Old docstring."
This can be fixed by setting the symbol property for
(put 'foo 'function-documentation nil)
I prefer the Common Lisp method.