From: Dr. Edmund Weitz
Subject: HANDLER-CASE and declarations
Date: 
Message-ID: <m3sn8lfr05.fsf@bird.agharta.de>
I'm confused. Consider the following code:

  (defparameter *error-message* nil)
  
  (handler-case
      (print 3)
    (arithmetic-error (var)
      (declare (ignore var)
               (special *error-message*))
      (setf *error-message* "Arithmetic error.")))
  
  (handler-case
      (print 3)
    (arithmetic-error ()
      (declare (special *error-message*))
      (setf *error-message* "Arithmetic error.")))
 
From my understanding of the CLHS entry, the two HANDLER-CASE forms
shown above should be equivalent. However, LispWorks (4.2) and CMUCL
(pre-18d) complain about a misplaced declaration in the second form.

What am I missing here?

Thank,
Edi.

From: Nils Goesche
Subject: Re: HANDLER-CASE and declarations
Date: 
Message-ID: <a3dslv$16n387$2@ID-125440.news.dfncis.de>
In article <··············@bird.agharta.de>, Dr. Edmund Weitz wrote:
> I'm confused. Consider the following code:
> 
>   (defparameter *error-message* nil)
>   
>   (handler-case
>       (print 3)
>     (arithmetic-error (var)
>       (declare (ignore var)
>                (special *error-message*))
>       (setf *error-message* "Arithmetic error.")))
>   
>   (handler-case
>       (print 3)
>     (arithmetic-error ()
>       (declare (special *error-message*))
>       (setf *error-message* "Arithmetic error.")))
>  
> From my understanding of the CLHS entry, the two HANDLER-CASE forms
> shown above should be equivalent. However, LispWorks (4.2) and CMUCL
> (pre-18d) complain about a misplaced declaration in the second form.
> 
> What am I missing here?

I'd say it's only a bug.  But you can just omit the declaration,
anyway, in this case :-)

Regards,
-- 
Nils Goesche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x42B32FC9
From: Pierre R. Mai
Subject: Re: HANDLER-CASE and declarations
Date: 
Message-ID: <878zade6p7.fsf@orion.bln.pmsf.de>
···@agharta.de (Dr. Edmund Weitz) writes:

> I'm confused. Consider the following code:

No, you are not! ;)

>   (defparameter *error-message* nil)
>   
>   (handler-case
>       (print 3)
>     (arithmetic-error (var)
>       (declare (ignore var)
>                (special *error-message*))
>       (setf *error-message* "Arithmetic error.")))
>   
>   (handler-case
>       (print 3)
>     (arithmetic-error ()
>       (declare (special *error-message*))
>       (setf *error-message* "Arithmetic error.")))
>  
> From my understanding of the CLHS entry, the two HANDLER-CASE forms
> shown above should be equivalent. However, LispWorks (4.2) and CMUCL
> (pre-18d) complain about a misplaced declaration in the second form.
> 
> What am I missing here?

Nothing, except that implementations are sometimes buggy.  In CMU CL,
the expansion of handler-case uses progn in the second case to contain
the body of the handler, where it should use locally (in order to
allow free declarations; since no variable is bound here, no bound
declarations could happen anyway, so no special handling of
declarations is necessary).  The first case is handled by a different
case of the macro code, which uses let, and hence automagically
handles free and bound declarations correctly.  Contrast the
expansions:

(BLOCK #:G899
  (LET ((#:G900 NIL))
    (DECLARE (IGNORABLE #:G900))
    (TAGBODY
      (HANDLER-BIND
       ((ARITHMETIC-ERROR
         #'(LAMBDA (CONDITIONS::TEMP)
             (SETQ #:G900 CONDITIONS::TEMP)
             (GO #:G901))))
       (RETURN-FROM #:G899
         (MULTIPLE-VALUE-PROG1 (PRINT 3) (KERNEL:FLOAT-WAIT))))
     #:G901
      (RETURN-FROM #:G899
        (LET ((VAR #:G900))
          (DECLARE (IGNORE VAR) (SPECIAL *ERROR-MESSAGE*))
          (SETF *ERROR-MESSAGE* "Arithmetic error."))))))

vs.

(BLOCK #:G902
  (LET ((#:G903 NIL))
    (DECLARE (IGNORABLE #:G903))
    (TAGBODY
      (HANDLER-BIND
       ((ARITHMETIC-ERROR
         #'(LAMBDA (CONDITIONS::TEMP)
             (DECLARE (IGNORE CONDITIONS::TEMP))
             (GO #:G904))))
       (RETURN-FROM #:G902
         (MULTIPLE-VALUE-PROG1 (PRINT 3) (KERNEL:FLOAT-WAIT))))
     #:G904
      (RETURN-FROM #:G902
        (PROGN
         (DECLARE (SPECIAL *ERROR-MESSAGE*))
         (SETF *ERROR-MESSAGE* "Arithmetic error."))))))


So the handler-case macro needs to use either locally or an empty let
here, instead of progn, to allow declarations in the body to work
correctly.

Since the CMU CL code is heavily based on the prototypical
implementation by KMP, it seems possible that LispWorks shares this
bug, because they based their implementation on the same code-base.

I've committed the appended fix to the repository, so that this
problem should be fixed in the upcoming 18d release...  Depending on
how similar the LispWorks code-base is, a similar change might fix
their bug.

Regs, Pierre.


Index: error.lisp
===================================================================
RCS file: /home/CVS-cmucl/src/code/error.lisp,v
retrieving revision 1.60
diff -U15 -F^(def -r1.60 error.lisp
--- error.lisp	2001/04/19 16:40:47	1.60
+++ error.lisp	2002/02/01 12:14:56
@@ -1072,31 +1072,31 @@ (defmacro handler-case (form &rest cases
 					 ;; Need to catch FP errors here!
 					 (kernel::float-wait))))
 		 ,@(mapcan
 		    #'(lambda (annotated-case)
 			(list (car annotated-case)
 			      (let ((body (cdddr annotated-case)))
 				`(return-from
 				  ,tag
 				  ,(cond ((caddr annotated-case)
 					  `(let ((,(caaddr annotated-case)
 						  ,var))
 					     ,@body))
 					 ((not (cdr body))
 					  (car body))
 					 (t
-					  `(progn ,@body)))))))
+					  `(locally ,@body)))))))
 			   annotated-cases))))))))
 
 (defmacro ignore-errors (&rest forms)
   "Executes forms after establishing a handler for all error conditions that
    returns from this form nil and the condition signalled."
   `(handler-case (progn ,@forms)
      (error (condition) (values nil condition))))
 
 
 
 ;;;; Restart definitions.
 
 (define-condition abort-failure (control-error) ()
   (:report
    "Found an \"abort\" restart that failed to transfer control dynamically."))

-- 
Pierre R. Mai <····@acm.org>                    http://www.pmsf.de/pmai/
 The most likely way for the world to be destroyed, most experts agree,
 is by accident. That's where we come in; we're computer professionals.
 We cause accidents.                           -- Nathaniel Borenstein