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

Example: (defgeneric foo (instance &rest initargs &key &allow-other-keys)) (defmethod foo ((cons cons) &key (car (car cons)) (cdr (cdr cons))) (setf (car cons) car (cdr cons) cdr) cons) (defmethod foo []) where [] is the point shows (defmethod foo (instance &rest initargs &key (cdr (cdr cons)) (car (car cons)) (imagpart (imagpart complex)) (realpart (realpart complex)) &allow-other-keys) &body body) in the minibuffer. Showing the CAR, CDR, IMAGPART and REALPART keys seems pretty pointless, and showing their initforms doubly so. Could we stick to the DEFGENERIC's lambda-list there, please? It's the one the method has to be congruent with. A related, but more blue-sky issue: In case of (foo []) the situation is better, but still having keywords from both lists is confusing. What could be really neat is that if after (foo x :car []) the minibuffer would display only the lambda lists for the methods for which :CAR is a legal keyword argument. Cheers, -- Nikodemus

On Sat, 9 May 2009 13:48:41 +0300, Nikodemus Siivola said:
Example:
(defgeneric foo (instance &rest initargs &key &allow-other-keys))
(defmethod foo ((cons cons) &key (car (car cons)) (cdr (cdr cons))) (setf (car cons) car (cdr cons) cdr) cons) <snip> A related, but more blue-sky issue: In case of
(foo [])
the situation is better, but still having keywords from both lists is confusing. What could be really neat is that if after
(foo x :car [])
the minibuffer would display only the lambda lists for the methods for which :CAR is a legal keyword argument.
It's a minefield, because the &allow-other-keys makes all keywords legal for all methods... __Martin

2009/5/11 Martin Simmons <martin@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
participants (2)
-
Martin Simmons
-
Nikodemus Siivola