Subject: bug#50834: closed (Re: bug#50834: Feature request: cl-remove-method (prototyped) and buttons for it)

From: [email-masked] (GNU bug Tracking System)
Date: Sun, 03 Sep 2023 08:39:02 +0000

Your bug report

#50834: Feature request: cl-remove-method (prototyped) and buttons for it

which was filed against the emacs package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
50834: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=50834
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: bug#50834: Feature request: cl-remove-method (prototyped) and buttons for it
From: Stefan Kangas <[email-masked]>
To: Lars Ingebrigtsen <[email-masked]>
Cc: [email-masked], Stefan Monnier <[email-masked]>, akater <[email-masked]>
Date: Sun, 3 Sep 2023 01:38:41 -0700
List-Id: <debbugs-submit.debbugs.gnu.org>

Lars Ingebrigtsen <[email-masked]> writes:

> Stefan Monnier <[email-masked]> writes:
>
>> Not much to say, except:
>>
>>> +  (cl-loop for k being hash-key in cl--generic-combined-method-memoization
>>> +           when (and (eq generic-function (car k))
>>> +                     (memq method (cdr k)))
>>> +           do (remhash k cl--generic-combined-method-memoization))
>>
>> I don't see why we'd need this.
>>
>> This is a cache that tries to speed up the construction of combined
>> methods, whereas in `cl-remove-method` we should only need to flush the
>> cache that maps tags to their corresponding combined methods and this is
>> done implicitly by `cl--generic-make-function` (which returns a new
>> function with a branch new fresh cache).
>
> Akater, do you have any comments (or an amended patch)?

More information was requested, but none was given within 10 months, so
I'm closing this bug.  If this is still an issue, please reply to this
email (use "Reply to all" in your email client) and we can reopen the
bug report.

Subject: Feature request: cl-remove-method (prototyped) and buttons for it
From: akater <[email-masked]>
To: [email-masked]
Date: Mon, 27 Sep 2021 01:09:00 +0000
List-Id: <debbugs-submit.debbugs.gnu.org>

I don't use CLOS or EIEIO very often but when I do, I remove methods all
the time.  I thus think it's a very important part of CLOS worflow.
SLIME inspector (for Common Lisp) offers buttons that remove methods on
the gf's page, e.g.:

Name: PRINT-OBJECT
Arguments: (SB-PCL::OBJECT STREAM)
Method class: #<STANDARD-CLASS COMMON-LISP:STANDARD-METHOD>
Method combination: #<SB-PCL::STANDARD-METHOD-COMBINATION STANDARD () {10002158A3}>
Methods: 
(TRACE-ENTRY T) [remove method]
(UNREADABLE-RESULT T) [remove method]
(CHANNEL T) [remove method]
(CONNECTION T) [remove method]
...

[remove method] are buttons.  Sadly, Elisp doesn't have an inspector but
I've heard of one effort github.com/mmontone/emacs-inspector and anyway,
these buttons would be appropriate in any displayed list of methods,
including the list currently shown in *Help* buffer for the gf.

Example:

Implementations:

[remove] :around (object stream) in ‘cl-print.el’.

Undocumented

[remove] ((object string) stream) in ‘cl-print.el’.

...

Recently it became necessary to use cl-remove-method in a library code
so I tried to write it.

The following seems to work but I'm very far from being confident about
it.  Also, methods are cached in lambdas returned by lambdas returned by
cl--generic-get-dispatcher, and I haven't yet figured out a way to get
them out of there; I'm also not sure if they should be removed manually,
or the tables will just get GC'ed given the proposed implementation of
cl-remove-method as is.

>From 50dc42ce1ea504657ccdcf85e9c71a2f27109610 Mon Sep 17 00:00:00 2001
From: akater <[email-masked]>
Date: Sun, 26 Sep 2021 21:33:46 +0000
Subject: [PATCH] Add cl-remove-method

---
 lisp/emacs-lisp/cl-generic.el | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el
index 1640975b84..7d5c8ddc0d 100644
--- a/lisp/emacs-lisp/cl-generic.el
+++ b/lisp/emacs-lisp/cl-generic.el
@@ -98,7 +98,7 @@
 ;; usually be simplified, or even completely skipped.
 
 (eval-when-compile (require 'cl-lib))
-(eval-when-compile (require 'cl-macs))  ;For cl--find-class.
+(eval-when-compile (require 'cl-macs))  ;For cl--find-class, cl-loop
 (eval-when-compile (require 'pcase))
 
 (cl-defstruct (cl--generic-generalizer
@@ -1255,6 +1255,35 @@ defun cl--generic-struct-specializers (tag &rest _)
 (cl--generic-prefill-dispatchers 0 integer)
 (cl--generic-prefill-dispatchers 0 cl--generic-generalizer integer)
 
+(cl-defmethod cl-remove-method ((generic-function cl--generic) method)
+  "An equivalent of Common Lisp's method for remove-method
+specialized on
+(COMMON-LISP:STANDARD-GENERIC-FUNCTION COMMON-LISP:METHOD)."
+  (setf (cl--generic-method-table generic-function)
+        ;; delq could cause bugs, let's see if it does
+        (delq method (cl--generic-method-table generic-function)))
+
+  (cl-loop for k being hash-key in cl--generic-combined-method-memoization
+           when (and (eq generic-function (car k))
+                     (memq method (cdr k)))
+           do (remhash k cl--generic-combined-method-memoization))
+
+  ;; It might make sense to move this
+  (defalias (cl--generic-name generic-function)
+    (cl--generic-make-function generic-function))
+  ;; to an :after method
+  ;; but it's not even clear to me whether
+  ;; having such :after method would be compatible with Common Lisp standard.
+  generic-function)
+
+(cl-defmethod cl-remove-method ((generic-function symbol) method)
+  "For Common Lisp compatibility in Elisp.
+
+Namely, (cl-remove-method #'f ..) should work correctly but #'f returns symbol in Elisp."
+  (if-let ((gf (cl--generic generic-function)))
+      (cl-remove-method gf method)
+    (error "No generic function named %s" generic-function)))
+
 ;;; Dispatch on major mode.
 
 ;; Two parts:
-- 
2.32.0