5
votes

This is a follow up to this previously asked question about the documentation function, which apparently deserved its own post.

Is there a way to dynamically get the docstring of either a function/macro OR a method in SBCL?

So far (documentation function-name 'function) gets me the docstring for regular functions (and I assume macros as well), but not methods. I tried 'method, 'standard-method and even 't but they don't seem to work.

My problem is that the environment I work with (in a visual programming interface based on Lisp) is filled with little engines that can be either functions or methods and I don't know how to differentiate them. I just need users to be able to get the docstring quickly for any given symbol (or tool) in the library, no matter its type, if it exists of course.

Thanks !

Julien

1
DESCRIBE would be more appropriate if you just want to view the documentation. DOCUMENTATION is only needed if you want to process the string somehow.jkiiski

1 Answers

6
votes

Symbols name functions, including macros and generic-functions, but not methods. In order to uniquely identify a method, you need to know the generic-function and all the applicable modifiers and specializers.

For example, PRINT-OBJECT names a generic function, but is not sufficient to refer to a specific methods. You can however iterate over all methods specializing a generic function and manipulate their documentation: instead of passing a name to DOCUMENTATION, you give the function object and T. In order to do this portably, use closer-mop:

(ql:quickload :closer-mop)

For example:

(lambda (generic-function)
  (map 'list
       (lambda (method) (documentation method t))
       (closer-mop:generic-function-methods generic-function)))
=> #<FUNCTION (LAMBDA (GENERIC-FUNCTION)) {1001BBCD3B}>

Let's try it:

CL-USER> (funcall * #'documentation)
(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)

Oops.

CL-USER> (defmethod documentation ((test (eql :test)) _) 
             "Test documentation" 
           "Returned value")
...
CL-USER> (documentation :test t)
"Returned value"

CL-USER> (funcall *** #'documentation)
("Test documentation" NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)