genericslispelispmethod-dispatchcl-lib

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


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?


Solution

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