How to add a new specializer to cl-defmethod apply to multiple major-modes?

425 Views Asked by At

How can I extend a cl-defmethod to match on multiple major-modes? There is a little documentation in cl-generic, but I don't understand what is going on with the generalizer macros.

As an example,

(cl-defgeneric my-gen-fun (arg)
  (message "%S" arg))

;; define this so it wouldn't affect other cc-derived modes, eg. java, awk, etc.
(cl-defmethod my-gen-fun (&context (major-mode c-mode c++-mode) arg)
  (message "c-%S" arg))

I would want (my-gen-fun arg) to only print "c-" in both c-mode and c++-mode, but not other cc-derived modes like java-mode or awk-mode. How can I add a new specializer to handle this case?

1

There are 1 best solutions below

2
Stefan On BEST ANSWER

The &context is like %optional in that it applies too all the subsequent args, so it has to come after the arguments.

But the (major-mode <foo>-mode) thingy does not extend to (major-mode <foo>-mode <bar>-mode) like you suggest (although it admittedly would be a natural extension). So instead you have to call cl-defmethod twice. If the body is large, you shoud probably put it into a separate function:

(defun my-gen-fun-c-body (arg)
  (message "c-%S" arg))

;; define this so it wouldn't affect other cc-derived modes, eg. java, awk, etc.
(cl-defmethod my-gen-fun (arg &context (major-mode c-mode))
   (my-gen-fun-c-body arg))
(cl-defmethod my-gen-fun (arg &context (major-mode c++-mode))
   (my-gen-fun-c-body arg))

I do have a local patch to cl-generic.el which adds the "multiple major modes" functionality you suggest, but after reviewing it I see that it's kind of a hack and introduces various corner-case problems.

Some of the corner case problems are related to the fact that CLOS does not offer something like or or and specializers like:

(defmethod foo ((x (or (eql 4) cons))) ...)

this is because it can make it "impossible" to find a sound ordering of the applicable methods (e.g.,is the above specializer more or less specific than (x list) or (x (or (eql 5) cons))?).