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

Previous Next

Package: emacs;

Reported by: akater <nuclearspace <at> gmail.com>

Date: Mon, 27 Sep 2021 01:21:01 UTC

Severity: wishlist

Tags: moreinfo

Done: Stefan Kangas <stefankangas <at> gmail.com>

Bug is archived. No further changes may be made.

To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 50834 in the body.
You can then email your comments to 50834 AT debbugs.gnu.org in the normal way.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-gnu-emacs <at> gnu.org:
bug#50834; Package emacs. (Mon, 27 Sep 2021 01:21:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to akater <nuclearspace <at> gmail.com>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs <at> gnu.org. (Mon, 27 Sep 2021 01:21:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: akater <nuclearspace <at> gmail.com>
To: bug-gnu-emacs <at> gnu.org
Subject: Feature request: cl-remove-method (prototyped) and buttons for it
Date: Mon, 27 Sep 2021 01:09:00 +0000
[Message part 1 (text/plain, inline)]
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.

[0001-Add-cl-remove-method.patch (text/x-diff, inline)]
From 50dc42ce1ea504657ccdcf85e9c71a2f27109610 Mon Sep 17 00:00:00 2001
From: akater <nuclearspace <at> gmail.com>
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


Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#50834; Package emacs. (Mon, 27 Sep 2021 14:56:02 GMT) Full text and rfc822 format available.

Message #8 received at 50834 <at> debbugs.gnu.org (full text, mbox):

From: akater <nuclearspace <at> gmail.com>
To: 50834 <at> debbugs.gnu.org
Subject: Re: Feature request: cl-remove-method (prototyped) and buttons for it
Date: Mon, 27 Sep 2021 14:44:13 +0000
[Message part 1 (text/plain, inline)]
Various fixes to the prototype patch:
- require subr-x
- more specific default signature
- more extensive documentation

[signature.asc (application/pgp-signature, inline)]
[0001-Add-cl-remove-method.patch (text/x-diff, inline)]
From decd4e0ed24553981f9b87f59308a10ccdd1c5b6 Mon Sep 17 00:00:00 2001
From: akater <nuclearspace <at> gmail.com>
Date: Sun, 26 Sep 2021 21:33:46 +0000
Subject: [PATCH] Add cl-remove-method

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

diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el
index 1640975b84..c1ef3af3c7 100644
--- a/lisp/emacs-lisp/cl-generic.el
+++ b/lisp/emacs-lisp/cl-generic.el
@@ -98,8 +98,9 @@
 ;; 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))
+(eval-when-compile (require 'subr-x))   ;if-let
 
 (cl-defstruct (cl--generic-generalizer
                (:constructor nil)
@@ -1255,6 +1256,59 @@ defun cl--generic-struct-specializers (tag &rest _)
 (cl--generic-prefill-dispatchers 0 integer)
 (cl--generic-prefill-dispatchers 0 cl--generic-generalizer integer)
 
+(cl-defgeneric cl-remove-method (generic-function method)
+  "Remove METHOD from GENERIC-FUNCTION by modifying the
+GENERIC-FUNCTION (if necessary).
+
+`cl-remove-method' does not signal an error if METHOD is not one
+of the methods on the GENERIC-FUNCTION.")
+
+(cl-defmethod cl-remove-method ((generic-function cl--generic)
+                                (method cl--generic-method))
+  "An equivalent of Common Lisp's default method for remove-method.
+
+Compatibility note:
+The Common Lisp HyperSpec page on remove-method says
+in Arguments and Values:
+  > method---a method
+and Exceptional Situations: none.
+So then, according to
+1.4.4.3 The ``Arguments and Values'' Section of a Dictionary Entry
+http://www.lispworks.com/reference/HyperSpec/Body/01_ddc.htm
+
+the consequences are undefined if the second value is not a method.
+
+In cl-generic, `cl-remove-method' is not applicable to
+non-methods by default."
+  ;; Credit for compatibility note goes to
+  ;; beach from #commonlisp at libera.chat
+  (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 cl--generic-method))
+  "For Common Lisp compatibility in Elisp.
+
+Namely, (cl-remove-method #'f ..) should work correctly but #'f
+returns symbol in Elisp, hence this method."
+  (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


Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#50834; Package emacs. (Fri, 02 Sep 2022 10:57:01 GMT) Full text and rfc822 format available.

Message #11 received at 50834 <at> debbugs.gnu.org (full text, mbox):

From: Lars Ingebrigtsen <larsi <at> gnus.org>
To: akater <nuclearspace <at> gmail.com>
Cc: Stefan Monnier <monnier <at> iro.umontreal.ca>, 50834 <at> debbugs.gnu.org
Subject: Re: bug#50834: Feature request: cl-remove-method (prototyped) and
 buttons for it
Date: Fri, 02 Sep 2022 12:56:05 +0200
akater <nuclearspace <at> gmail.com> writes:

> +(cl-defgeneric cl-remove-method (generic-function method)
> +  "Remove METHOD from GENERIC-FUNCTION by modifying the
> +GENERIC-FUNCTION (if necessary).

I think this sounds very useful -- I don't think we have any other ways
to remove a method, and that's something that I've been missing
sometimes when implementing stuff.

Perhaps Stefan has some comments here; added to the CCs.





Added tag(s) moreinfo. Request was from Lars Ingebrigtsen <larsi <at> gnus.org> to control <at> debbugs.gnu.org. (Fri, 02 Sep 2022 10:57:02 GMT) Full text and rfc822 format available.

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#50834; Package emacs. (Fri, 02 Sep 2022 13:30:02 GMT) Full text and rfc822 format available.

Message #16 received at 50834 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Lars Ingebrigtsen <larsi <at> gnus.org>
Cc: akater <nuclearspace <at> gmail.com>, 50834 <at> debbugs.gnu.org
Subject: Re: bug#50834: Feature request: cl-remove-method (prototyped) and
 buttons for it
Date: Fri, 02 Sep 2022 09:29:16 -0400
Lars Ingebrigtsen [2022-09-02 12:56:05] wrote:
> akater <nuclearspace <at> gmail.com> writes:
>> +(cl-defgeneric cl-remove-method (generic-function method)
>> +  "Remove METHOD from GENERIC-FUNCTION by modifying the
>> +GENERIC-FUNCTION (if necessary).
> I think this sounds very useful -- I don't think we have any other ways
> to remove a method, and that's something that I've been missing
> sometimes when implementing stuff.

I'd challenge your use of "very", but I agree it's missing.

> Perhaps Stefan has some comments here; added to the CCs.

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


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#50834; Package emacs. (Tue, 04 Oct 2022 12:20:02 GMT) Full text and rfc822 format available.

Message #19 received at 50834 <at> debbugs.gnu.org (full text, mbox):

From: Lars Ingebrigtsen <larsi <at> gnus.org>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: akater <nuclearspace <at> gmail.com>, 50834 <at> debbugs.gnu.org
Subject: Re: bug#50834: Feature request: cl-remove-method (prototyped) and
 buttons for it
Date: Tue, 04 Oct 2022 14:19:44 +0200
Stefan Monnier <monnier <at> iro.umontreal.ca> 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)?




Reply sent to Stefan Kangas <stefankangas <at> gmail.com>:
You have taken responsibility. (Sun, 03 Sep 2023 08:39:02 GMT) Full text and rfc822 format available.

Notification sent to akater <nuclearspace <at> gmail.com>:
bug acknowledged by developer. (Sun, 03 Sep 2023 08:39:02 GMT) Full text and rfc822 format available.

Message #24 received at 50834-done <at> debbugs.gnu.org (full text, mbox):

From: Stefan Kangas <stefankangas <at> gmail.com>
To: Lars Ingebrigtsen <larsi <at> gnus.org>
Cc: 50834-done <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>,
 akater <nuclearspace <at> gmail.com>
Subject: Re: bug#50834: Feature request: cl-remove-method (prototyped) and
 buttons for it
Date: Sun, 3 Sep 2023 01:38:41 -0700
Lars Ingebrigtsen <larsi <at> gnus.org> writes:

> Stefan Monnier <monnier <at> iro.umontreal.ca> 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.




bug archived. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Sun, 01 Oct 2023 11:24:13 GMT) Full text and rfc822 format available.

This bug report was last modified 208 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.