The less-familiar parts of Lisp for beginners — remove-method

Now we come to another Lisp feature with no real analogue in C++, the standard generic function remove-method.  What this function does is to undo the effect of a defmethod construct, at run time.  That is, the Lisp image can forget about a specialized method.  As we’ve noted several times in the past, this difference comes about because of a fundamental difference in the way Lisp and C++ runtime environments are handled.  In C++, you modify the source code, recompile the binary, and then restart the program.  In Lisp, the image itself contains the methods, functions, and data that any Lisp program might want to use, but it’s better not to think of the program as really existing, it’s more like a context that happens to be executing functions at the moment.

In fact, now that I think of it, a C++ programmer might better understand a Lisp “program” as a particular thread executing in a larger context.  The thread has an associated stack and local data, and runs through certain functions, and maybe eventually exits, but does all this in the context of a sea of functions and methods available to it.  Different threads can run entirely different “programs”, and as long as nobody starts messing around with global state, these programs don’t even know about one another.  So, think of your C++ program was really just a launching pad for these threads, and you have the ability to modify methods and classes on the fly then run a “program” thread using the updated binary image.  That’s a bit like how you can view the Lisp runtime environment.

So, remove-method removes a specialized method, as if the corresponding defmethod had never been loaded.  Here’s an example of this in use.  I create a base class and a derived class, each with different methods for do-something.  Then, I make an instance of the derived class, and I locate the method specialized on the derived class.  The first time I call do-something, it uses the method for the derived class.  Then, I call remove-method on that method, and call do-something again.  Now, with no specialized method for the derived class, the base-class method is called instead:
remove-method.lisp

(defclass base-class ()
  ())

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

(defgeneric do-something (obj))

(defmethod do-something ((obj base-class))
  (format t "Called do-something in the base class.~%"))

(defmethod do-something ((obj derived-class))
  (format t "Called do-something in the derived class.~%"))

(defun demonstrate ()
  (let ((obj (make-instance 'derived-class))
        (specialized 
         (find-method #'do-something
                      '()
                      (list (find-class 'derived-class)))))
    (do-something obj)
    (remove-method #'do-something specialized)
    (do-something obj)))

With output:
*slime-repl sbcl*
CL-USER> (demonstrate)
Called do-something in the derived class.
Called do-something in the base class.
NIL

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.