4

Is there a way to extract a list of methods from a generic function in Common Lisp?
For example:

(defmethod say ((self string)) ; method-0
  (format t "Got string: ~a~%" self))

(defmethod say ((self integer)) ; method-1
  (format t "Got integer: ~a~%" self))

(defmethod say ((self symbol)) ; method-2
  (format t "Got symbol: ~a~%" self))

(extract-methods-from-generic 'say) ; -> (method-0-obj method-1-obj method-2-obj)

To be more specific, I'm targeting ECL, so if this can be done via C API - that's ok.
I need this to do the next trick:

(defgeneric merged-generic ())

(loop for method
      in (extract-methods-from-generic 'some-generic-0)
      do (add-method merged-generic method))
(loop for method
      in (extract-methods-from-generic 'some-generic-1)
      do (add-method merged-generic method))
Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
AlexDarkVoid
  • 485
  • 3
  • 12

1 Answers1

5

The generic function generic-function-methods is available in the CLOS to get all the methods of a generic function (see the CLOS protocol), but note that, for the second part of your question, you can attach a method to a generic function (with add-method) only if the method is detached from any other generic function (see the protocol):

An error is also signaled if the method is already associated with some other generic function.

You can use both of those functions through the package closer-mop, independently from any implementation:

CL-USER> (ql:quickload "closer-mop") 
("closer-mop")
CL-USER> (in-package :closer-mop)
#<Package "CLOSER-MOP">
C2MOP> (defgeneric say (x))
#<COMMON-LISP:STANDARD-GENERIC-FUNCTION SAY #x30200176712F>
C2MOP> (defmethod say ((self string)) ; method-0
  (format t "Got string: ~a~%" self))

(defmethod say ((self integer)) ; method-1
  (format t "Got integer: ~a~%" self))

(defmethod say ((self symbol)) ; method-2
  (format t "Got symbol: ~a~%" self))
#<COMMON-LISP:STANDARD-METHOD SAY (SYMBOL)>
C2MOP> (generic-function-methods #'say)
(#<COMMON-LISP:STANDARD-METHOD SAY (SYMBOL)> #<COMMON-LISP:STANDARD-METHOD SAY (INTEGER)> #<COMMON-LISP:STANDARD-METHOD SAY (STRING)>)
C2MOP> (defgeneric merged-generic (x))
#<COMMON-LISP:STANDARD-GENERIC-FUNCTION MERGED-GENERIC #x30200181B74F>
C2MOP> (add-method #'merged-generic (first **))

#<COMMON-LISP:STANDARD-METHOD SAY (SYMBOL)> is already a method of #<COMMON-LISP:STANDARD-GENERIC-FUNCTION SAY #x30200165863F>.
   [Condition of type SIMPLE-ERROR]
; Evaluation aborted on #<SIMPLE-ERROR #x3020016719FD>.
CL-USER> (let ((first-method (first (generic-function-methods #'say))))
           (remove-method #'say first-method)
           (add-method #'merged-generic first-method))
#<COMMON-LISP:STANDARD-GENERIC-FUNCTION MERGED-GENERIC #x302000DC54DF>
CL-USER> (merged-generic "a string")
Got string: a string
NIL
Renzo
  • 26,848
  • 5
  • 49
  • 61
  • 1
    Okay, but is it possible to 'clone' a method and attach its copy to another generic function? – AlexDarkVoid Mar 06 '17 at 12:51
  • You could look at the answers to this question: http://stackoverflow.com/questions/11067899/is-there-a-generic-method-for-cloning-clos-objects – Renzo Mar 06 '17 at 13:00
  • 1
    @Renzo Thats clonig an object. He wants to make a merge between the two generic methods without destroying the originals, which is done in this answer. Perhaps one could proxy it somehow? – Sylwester Mar 06 '17 at 15:40