Subject: defmethod lambda list bug

From: [email-masked] (Rick Taube)
Date: Mon, 2 May 94 16:29:08 GMT+0100

theres a bug in clisp's defmethod that doesn't allow both optional  
and keyword arguments to be supplied in a calling form. is there a  
workaround aready available?? ive also tried adding a &rest before  
the &key but it doesnt help. im using the clisp from  
clisp/binaries/next, (lisp-implementation-version)
"January 1994"
	-hkt
	
> (in-package :clos)
#<PACKAGE CLOS>
> (defmethod foo (a &optional b &key c))
#<STANDARD-METHOD (#<BUILT-IN-CLASS T>)>
> (foo 1 2 :c 3)

*** - EVAL/APPLY: keyword arguments for #<COMPILED-CLOSURE  
#:COMPILED-FORM-49-1> should occur pairwise
1. Break> backtrace-1

- NIL
- #<SIMPLE-ERROR #x000014>
frame binding variables (~ = dynamically):
  | ~ SYSTEM::*PRIN-STREAM* <--> #<UNBOUND>
- #<SIMPLE-ERROR #x000014>
- #<COMPILED-CLOSURE #:COMPILED-FORM-49-1>
- 3
- :C
- 2
- #<UNBOUND>
- #<UNBOUND>
- 1
- #<COMPILED-CLOSURE #:COMPILED-FORM-49-1>
- #<GENERIC-FUNCTION FOO>
- (2 :C 3)
- 1
- #<GENERIC-FUNCTION FOO>
EVAL frame for form (FOO 1 2 :C 3)
- #<CONCATENATED-STREAM #<STRING-INPUT-STREAM> #<SYNONYM-STREAM  
*TERMINAL-IO*>>
- #<SYNONYM-STREAM *TERMINAL-IO*>
1. Break>

---

From: haible (Bruno Haible)
Date: Mon, 2 May 94 18:23:25 +0200

Rick Taube <[email-masked]> writes:

> and keyword arguments to be supplied in a calling form.

Yes. Please patch clos.lsp:

*** clos.lsp.orig       Mon Jan  3 03:40:20 1994
--- clos.lsp    Mon May  2 18:07:07 1994
***************
*** 2493,2500 ****
           (apply-fun (if restp 'APPLY 'FUNCALL))
           (apply-args `(,@req-vars ,@(if restp `(,rest-var) '())))
           (lambdalist `(,@req-vars ,@(if restp `(&REST ,rest-var) '())))
           (key-vars '())
!          (lambdalist-with-key lambdalist)
           (arg-order (gf-argorder gf))
           (methods (gf-methods gf)))
      ; Determine the effective method:
--- 2493,2501 ----
           (apply-fun (if restp 'APPLY 'FUNCALL))
           (apply-args `(,@req-vars ,@(if restp `(,rest-var) '())))
           (lambdalist `(,@req-vars ,@(if restp `(&REST ,rest-var) '())))
+          (opt-vars '())
           (key-vars '())
!          (lambdalist-keypart '())
           (arg-order (gf-argorder gf))
           (methods (gf-methods gf)))
      ; Determine the effective method:
***************
*** 2532,2541 ****
                          (append (fourth signature) (mapcap #'fifth signatures))
                          :from-end t
                     )) )
                  (setq key-vars (n-gensyms (length keywords)))
!                 (setq lambdalist-with-key
!                       `(,@lambdalist
!                         &KEY
                          ,@(mapcar #'(lambda (kw var) `((,kw ,var)))
                                    keywords key-vars
                            )
--- 2533,2542 ----
                          (append (fourth signature) (mapcap #'fifth signatures))
                          :from-end t
                     )) )
+                 (setq opt-vars (n-gensyms (second signature)))
                  (setq key-vars (n-gensyms (length keywords)))
!                 (setq lambdalist-keypart
!                       `(&KEY
                          ,@(mapcar #'(lambda (kw var) `((,kw ,var)))
                                    keywords key-vars
                            )
***************
*** 2617,2627 ****
          (let* ((ef-form (ef-1 primary-methods before-methods after-methods around-methods))
                 (ef-fun (if (and (eq (car ef-form) apply-fun)
                                  (equal (cddr ef-form) apply-args)
!                                 (equal lambdalist lambdalist-with-key)
                             )
                           (cadr ef-form)
!                          `#'(LAMBDA ,lambdalist-with-key
!                               ,@(if key-vars `((DECLARE (IGNORE ,@key-vars))))
                                ,ef-form
                              )
                ))       )
--- 2618,2638 ----
          (let* ((ef-form (ef-1 primary-methods before-methods after-methods around-methods))
                 (ef-fun (if (and (eq (car ef-form) apply-fun)
                                  (equal (cddr ef-form) apply-args)
!                                 (null lambdalist-keypart)
                             )
                           (cadr ef-form)
!                          `#'(LAMBDA
!                               ,@(if (null opt-vars)
!                                   `(,(append lambdalist lambdalist-keypart)
!                                     ,@(if key-vars `((DECLARE (IGNORE ,@key-vars))))
!                                    )
!                                   `(,lambdalist
!                                     (APPLY #'(LAMBDA (&OPTIONAL ,@opt-vars ,@lambdalist-keypart)
!                                                (DECLARE (IGNORE ,@opt-vars ,@key-vars))
!                                              )
!                                            ,rest-var
!                                    ))
!                                 )
                                ,ef-form
                              )
                ))       )

To regenerate lispinit.mem without rebuilding clisp from scratch:
"clisp -c clos", "clisp -i clos -x '(saveinitmem)'" won't work.
You have to set up a file closfix.lsp which contains the line
(in-package "CLOS")
and the definition of compute-effective-method
from the fixed clos.lsp and use this instead:
"clisp -c closfix", "clisp -i closfix -x '(saveinitmem)'"

                    Bruno Haible
                    [email-masked]