The less-familiar parts of Lisp for beginners — compute-applicable-methods

Continuing with some less familiar parts of Lisp from the C++ programmer’s perspective, we come to compute-applicable-methods.  For the programmer, this is most commonly going to be used for insight into the method combination mechanism.  Recall our discussion of call-next-method, there is a set of rules that describes how the method to be invoked is chosen.  There is a default set of rules, but the programmer can also write his or her own combination rules for certain classes.  When the code encounters a generic function invocation, it will choose a method to execute on the arguments, using compute-applicable-methods.

The beginner programmer can use this function to understand how the method is chosen.  The function returns a list of methods, in precedence order.  Here is a demonstration of this use:
 

;; Demonstrate compute-applicable-methods


(defclass base-class ()
  ())

(defclass derived-class (base-class)
  ())

(defgeneric myprint (stream object)
  (:documentation "Prints to 'stream' some information about 'object'."))

(defmethod myprint (stream (object base-class))
  (format t "Entering base-class primary method.~%")
  (format t "Leaving base-class primary method.~%"))

(defmethod myprint :around (stream (object base-class))
  (format t "Entering base-class :around method.~%")
  (format t "Calling next method.~%")
  (call-next-method)
  (format t "Leaving base-class :around method.~%"))

(defmethod myprint (stream (object derived-class))
  (format t "Entering derived-class primary method.~%")
  (format t "Leaving derived-class primary method.~%"))

(defun demonstrate ()
  (let ((base (make-instance 'base-class))
        (derived (make-instance 'derived-class)))
    (format t "The applicable methods list on base-class for 'myprint is:~%")
    (format t "~A~%~%" (compute-applicable-methods #'myprint 
                                                   (list t base)))
    (format t "And now we run 'myprint on a base-class object:~%")
    (myprint t base)

    (format t "~%~%")

    (format t "The applicable methods list on derived-class for 'myprint is:~%")
    (format t "~A~%~%" (compute-applicable-methods #'myprint 
                                                   (list t derived)))
    (format t "And now we run 'myprint on a derived-class object:~%")
    (myprint t derived)))

Producing output as follows:
 
CL-USER> (demonstrate)
The applicable methods list on base-class for 'myprint is:
(#<STANDARD-METHOD MYPRINT :AROUND (T BASE-CLASS) {100CEC1243}>
 #<STANDARD-METHOD MYPRINT (T BASE-CLASS) {100CD87083}>)

And now we run 'myprint on a base-class object:
Entering base-class :around method.
Calling next method.
Entering base-class primary method.
Leaving base-class primary method.
Leaving base-class :around method.

The applicable methods list on derived-class for 'myprint is:
(#<STANDARD-METHOD MYPRINT (T DERIVED-CLASS) {100CF3AB63}>
 #<STANDARD-METHOD MYPRINT :AROUND (T BASE-CLASS) {100CEC1243}>
 #<STANDARD-METHOD MYPRINT (T BASE-CLASS) {100CD87083}>)

And now we run 'myprint on a derived-class object:
Entering base-class :around method.
Calling next method.
Entering derived-class primary method.
Leaving derived-class primary method.
Leaving base-class :around method.
NIL

You’ll notice that, for the derived class, it looks as if the order is wrong, because the base-class :around method was called, not the derived-class primary method.  Under method combination rules, if there are any :around methods, then the most specific :around method is invoked instead of any primary methods.  If that :around method invokes call-next-method, it then goes on through the rules we detailed before, under call-next-method.  So, the :around method, though second in the list of returned methods, overrides the more specific primary method.  Then, because of the call-next-method form, the more specific primary method is called.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

反垃圾邮件 / Anti-spam question * Time limit is exhausted. Please reload CAPTCHA.