Macros like defun (or defmacro itself) have an optional docstring argument, but since they are macros and not functions, docstring isn't evaluated, but is taken as-is.

I need the docstring to be evaluated so that instead of something like this -

"does a, then b, then c" ; b is hardcoded

I can put something like this instead -

(concat "does a, then " (getenv "<some-shell-variable>") " , then c") ; b isn't hardcoded

Is it possible to do this without having to tweak the definitions of defun and defmacro?

By tweak, I don't mean overwriting the definitions, but writing new macros like prefix-defun and prefix-defmacro based on the existing definitions of defun and demacro, except, the docstring is evaluated by replacing all instances of docstring with (eval docstring).


You can set the doc string of any function, variable, or face to any string you want, whether (generated dynamically or not).

For a function foo, put the string you want on symbol foo as the value of property function-documentation:

(defun foo () ; `foo' gets no doc string from this defun.
  (message "FOOOOOOOO"))

(put 'foo 'function-documentation "I'm `foo'.") ; Give function `foo' a doc string.
(put 'foo 'function-documentation "I'm NEW `foo' doc.") ; Redefine the doc string.

Same thing for a defvar or defcustom - use symbol property variable-documentation:

(defvar foo 42) ; Variable `foo' has no doc string.

(put 'foo 'variable-documentation "I'm `foo'.") ; Give var `foo' a doc string.
(put 'foo 'variable-documentation "I'm NEW `foo' .") ; Redefine the doc string.

See the Elisp manual, node Documentation Basics and its subnodes.

Same thing for defface- use symbol property variable-documentation. But defface requires a doc string. You can nevertheless change it dynamically, as you can for a function or variable.

(defface foo '((t :foreground "Red")) "0000") ; Doc string "0000".

(put 'foo 'face-documentation "11111") ; Change doc string to "1111".
  • Perfect, it works first of all and I really like this solution (symbol properties). – nomad Sep 28 '20 at 5:35
(defun foo ()
  (:documentation (concat "does a, then " (getenv "<some-shell-variable>") " , then c"))

This is effectively a duplicate of Is it possible to attach generated doc string to a lambda? except that question is very lambda-oriented, and so Stefan's answer doesn't point out that you can do the same thing with defun.

If you need the docstring to be eval'd on-demand (i.e. every time you request it), you can do that as well, but apparently not with :documentation. Refer to my answer to the earlier question for some options for doing that.

  • *** Eval error *** Symbol’s function definition is void: :documentation, I tried it on defmacro. Both : and documentation are defined. – nomad Sep 27 '20 at 13:05
  • I've just tested, and :documentation works fine for defmacro in Emacs 27.1. Alternatively, try using the function-documentation symbol property instead. – phils Sep 27 '20 at 13:27
  • I suspect you put (:documentation...) into the macro's return value, though. Don't do that. – phils Sep 27 '20 at 13:31
  • Very strange, works perfectly when I run it in ielm, but if I put it in the init file, I get the error. – nomad Sep 27 '20 at 15:55
  • I'm not sure what's going on there, then. Personally I've always used defalias or the function-documentation symbol property to assign docstrings in atypical situations... The :documentation declaration had seemed to me like the best suggestion here, and had worked for me in cursory tests, but perhaps it has some quirks. – phils Sep 27 '20 at 22:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.