1

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).

nomad
  • 247
  • 1
  • 6

2 Answers2

3
(defun foo ()
  (:documentation (concat "does a, then " (getenv "<some-shell-variable>") " , then c"))
  ...BODY...)

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.

phils
  • 48,657
  • 3
  • 76
  • 115
  • ```*** 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
  • Considering `defun` and `defmacro` are ultimately using `defalias`, maybe a custom function object would do. – nomad Sep 28 '20 at 06:06
0

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.
  (interactive)
  (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".
Drew
  • 75,699
  • 9
  • 109
  • 225