[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