How can I extend a cl-defmethod
to match on multiple major-mode
s? 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?
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))
?).