[slime-devel] non-helpful argument list display for defmethod

Nikodemus Siivola nikodemus at random-state.net
Wed May 13 17:45:24 UTC 2009


2009/5/11 Martin Simmons <martin at lispworks.com>:

> It's a minefield, because the &allow-other-keys makes all keywords legal for
> all methods...

Right. My example was bad due to the &allow-other-keys. Here's a bit
of code that does what I want in SBCL -- portable version needs
%SPLIT-ARGLIST and FUNCTION-KEYWORD-PARAMETERS (which can be replaced
with FUNCTION-KEYWORDS.)

No comments on how tricky it would be too hook up to slime:

Examples:

(defgeneric foo (object &rest initargs &key))

(generic-function-lambda-list-using-keys #'foo nil)            ; =>
(OBJECT &REST INITARGS &KEY)

(defmethod foo ((cons cons) &key car cdr)
  (cons car cdr))

(defmethod foo ((complex complex) &key realpart imagpart)
  (complex realpart imagpart))

(generic-function-lambda-list-using-keys #'foo nil)          ; =>
(OBJECT &REST INITARGS &KEY CDR CAR IMAGPART REALPART)
(generic-function-lambda-list-using-keys #'foo '(:realpart)) ; =>
(OBJECT &REST INITARGS &KEY REALPART IMAGPART)
(generic-function-lambda-list-using-keys #'foo '(:cdr))      ; =>
(OBJECT &REST INITARGS &KEY CAR CDR)
(generic-function-lambda-list-using-keys #'foo '(:zot))      ; =>
(OBJECT &REST INITARGS)

Code:

(in-package :sb-pcl)

;; Adapted from SB-PCL::GENERIC-FUNCTION-PRETTY-ARGLIST
(defmethod generic-function-lambda-list-using-keys (generic-function req-keys)
  (let ((gf-lambda-list (generic-function-lambda-list generic-function))
        (methods (generic-function-methods generic-function)))
    (if (null methods)
        gf-lambda-list
        (multiple-value-bind (gf.required gf.optional gf.rest gf.keys gf.allowp)
            (%split-arglist gf-lambda-list)
          ;; Possibly extend the keyword parameters of the gf by additional
          ;; key parameters of those methods that include requested keys not
          ;; in the generic function lambda-list.
          (let ((methods.keys nil) (methods.allowp nil))
            (dolist (m methods)
              (multiple-value-bind (m.keywords m.allow-other-keys)
(function-keywords m)
                (when (or gf.allowp m.allow-other-keys
                          (every (lambda (key)
                                   (member key m.keywords :key #'maybe-car))
                                 req-keys))
                  (multiple-value-bind (keyparams allowp)
(function-keyword-parameters m)
                    (setq methods.keys (union methods.keys keyparams
:key #'maybe-car))
                    (setq methods.allowp (or methods.allowp allowp))))))
            (let ((arglist '()))
              (when (or gf.allowp methods.allowp)
                (push '&allow-other-keys arglist))
              (when (or gf.keys methods.keys)
                ;; We make sure that the keys of the gf appear before
                ;; those of its methods, since they're probably more
                ;; generally appliable.
                (setq arglist (nconc (list '&key) gf.keys
                                     (nset-difference methods.keys gf.keys)
                                     arglist)))
              (when gf.rest
                (setq arglist (nconc (list '&rest gf.rest) arglist)))
              (when gf.optional
                (setq arglist (nconc (list '&optional) gf.optional arglist)))
              (nconc gf.required arglist)))))))

Perhaps Slime could:

1. Use GENERIC-FUNCTION-LAMBDA-LIST for DEFMETHOD lambda-list hinting.
Collecting keywords from all methods is not helpful there as far as I
can see.

2. Use something akin to above for GF call lambda-list hinting --
passing in the list of keys already typed as the second argument.

Cheers,

 -- Nikodemus




More information about the slime-devel mailing list