Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove one method from a generic function

I have added the following method to the generic function speak but would now like to remove this particular method in the REPL without removing the rest of the generic functions' methods.

(defmethod speak :around ((c courtier) string)           ; [1]
  (format t "Does the King believe that ~A?" string)
  (if (eql (read) 'yes)
      (if (next-method-p) (call-next-method))            ; [2]
      (format t "Indeed, it is a preposterous idea.~%"))
  'bow)

[1] The :around method replaces the primary method for the type.
[2] Then it decides whether to call the primary method or not.

The documentation link to the function remove-method has no examples and I don't know what is the syntax to refer to the actual :around method above.

(remove-method #'speak)
TOO FEW ARGUMENTS

(remove-method #'speak :around)
NO-APPLICABLE-METHOD

like image 209
mwal Avatar asked Aug 09 '19 05:08

mwal


2 Answers

From the documentation:

remove-method generic-function method

It expects a generic function object and a method object as arguments.

One can find the method via find-method.

CL-USER 39 > (find-method #'speak
                          (list :around)
                          (list (find-class 'courtier) (find-class t)))
#<STANDARD-METHOD SPEAK (:AROUND) (COURTIER T) 42001285EB>

CL-USER 40 > (remove-method #'speak
                            (find-method #'speak
                                         (list :around)
                                         (list (find-class 'courtier)
                                         (find-class t))))
#<STANDARD-GENERIC-FUNCTION SPEAK 422000A68C>

Note also that a good Lisp development environment may also allow to remove methods in the editor or the inspector.

Note that in the Lisp listener, one does not need to call find-method twice like above. The variable * contains the last result.

CL-USER 43 > (find-method #'speak
                          (list :around)
                          (list (find-class 'courtier)
                                (find-class t)))
#<STANDARD-METHOD SPEAK (:AROUND) (COURTIER T) 4200150DEB>

CL-USER 44 > (remove-method #'speak *)
#<STANDARD-GENERIC-FUNCTION SPEAK 422000A68C>

Here is another interaction example using SLIME in GNU Emacs with the presentation feature for SLIME enabled. A presentation is Lisp output, which keeps the connection between the printed object and the generated text.

Slime REPL

Call the find-method function. It returns the method. Here we use presentations, which keep the connections between text and Lisp objects. The output is displayed in the color red and it is mouse-sensitive. Moving the mouse over the red returned object will add interaction options.

Now type (remove-method #'speak and then middle-click (or whatever SLIME is configured to use) on the red output: the presentation (the text and the connected object) will be copied to the line. Type ) and enter the form. SLIME has actually constructed a list with the real object and not the textual representation, then.

This is how repls work on the Symbolics Lisp Machine and in CLIM / McCLIM...

like image 165
Rainer Joswig Avatar answered Oct 31 '22 10:10

Rainer Joswig


If using GNU Emacs with SLIME, you can also use slime-inspector. For example define generic function foo and two methods:

USER> (defgeneric foo (x))
#<STANDARD-GENERIC-FUNCTION FOO (0)>

USER> (defmethod foo ((x string)) (length x))
#<STANDARD-METHOD FOO (STRING) {100B4D7E23}>

USER> (defmethod foo ((x integer)) x)
#<STANDARD-METHOD FOO (INTEGER) {100C355843}>

You have two main options to enter the inspector:

  1. From the REPL, type #'foo so that a presentation object for the generic method is printed:

    USER> #'foo
    #<STANDARD-GENERIC-FUNCTION FOO (0)>
    

    Either right-click the presentation (anywhere inside #<...>) and select Inspect, or put the cursor in the presentation and press C-c C-v TAB (slime-inspect-presentation-at-point).

  2. From a source file, enter slime-inspect, a.k.a. C-c I, and enter #'foo.

In both cases, you are shown a view similar to this:

#<STANDARD-GENERIC-FUNCTION {505A9A2B}>
--------------------
Name: FOO
Arguments: (X)
Method class: #<STANDARD-CLASS COMMON-LISP:STANDARD-METHOD>
Method combination: #<SB-PCL::STANDARD-METHOD-COMBINATION STANDARD () {1000214003}>
Methods: 
(INTEGER) [remove method]
(STRING) [remove method]

(....)

Each [remove method] text is actually a button, click or press Return on any of them to remove the associated method from the generic function.

like image 32
coredump Avatar answered Oct 31 '22 11:10

coredump