Remove one method from a generic function
Asked Answered
N

2

8

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

Nanon answered 9/8, 2019 at 5:57 Comment(3)
duplicate: #5976970Selwyn
yes - might be worth mentioning though that the duplicate uses slightly different terminology, so i don't think I would have known to search for it & why i didn't find it.Nanon
absolutely. Yours is easier to find (so a redirection from here to the answer would have worked).Selwyn
J
10

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...

Judiejudith answered 9/8, 2019 at 7:1 Comment(3)
To clarify why i cannot paste the REPL output from find-method as arg to remove-method (That gives the error "objects printed with #<...> cannot be read back in"), can we be more specific when we say "find the method"? Can we say "find the internal representation of the method"? What would be good language to use there? Would it be right to say that's a pointer to the method?Nanon
@mwal: No, we find the method itself. What you try is to copy text, not the method. Actually, there are Lisp systems where you can copy the object in 'repl'.Judiejudith
@mwal: if you want to reuse an evaluation result in the 'repl' / 'listener', then use variables like *, **, ***, which are bound to prior results.Judiejudith
R
3

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.

Ribosome answered 9/8, 2019 at 7:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.