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 post uses
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 argument.
(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 function.
(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
documentation function will prefer this over the string stored in the function itself.
(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.blog comments powered by Disqus