Subject: A bug in the new ANSI loop macro

From: "David J. Fiander" <[email-masked]>
Date: Mon, 10 Apr 1995 17:08:50 -0400

I have the following code:

	(loop for char across fmt
	      do
	      (incf skip)
	      (case char
		(#\@ (setf at t))
		(#\: (setf colon t)))
	      until (operatorp char)
	      finally (setf cmd char))

(I'm trying to write the (formatter) macro.)  The problem is that
clisp reports

	*** - EVAL: variable CHAR has no value

in the "finally" clause.  This works for the example

	 (for i from 1 to 10...

example from Steele.  The problem is that the macroexpansion puts
the finally clause in a different scope when using the "across"
syntax:

(MACROLET ((LOOP-FINISH NIL (SYSTEM::LOOP-FINISH-ERROR)))
  (BLOCK NIL
    (LET NIL
      (LET ((#:G530 FMT) (#:G531 0))
	   (MACROLET ((LOOP-FINISH NIL '(GO SYSTEM::END-LOOP)))
	     (TAGBODY SYSTEM::BEGIN-LOOP
		      (PROGN (WHEN (>= #:G531 (LENGTH #:G530)) (LOOP-FINISH)))
		      (LET ((CHAR (AREF #:G530 #:G531)))
			   (PROGN
			    (PROGN (INCF SKIP)
				   (CASE CHAR
					 (#\@ (SETF AT T))
					 (#\: (SETF COLON T))))
			    (WHEN (OPERATORP CHAR) (LOOP-FINISH))))
		      (PROGN (PSETQ #:G531 (1+ #:G531)))
		      (GO SYSTEM::BEGIN-LOOP)
		      SYSTEM::END-LOOP
		      (MACROLET
		       ((LOOP-FINISH NIL (SYSTEM::LOOP-FINISH-WARN) '(GO SYSTEM::END-LOOP)))
		       (PROGN (SETF CMD CHAR)))))))))

This is clearly beyond my current level of lisp programming.

- David

---

From: David Gadbois <[email-masked]>
Date: Wed, 12 Apr 1995 12:07:41 -0500

Date: Wed, 12 Apr 95 15:07:12 +0200
   From: "David J. Fiander" <[email-masked]>

A close reading of X3J13-94-101 and the issue history indicates that
clisp is correct, at least insofar as the standard is purposefully
vague on the issue.  The only LOOP bindings available in FINALLY
clauses are ones created by WITH clauses (and, by extension, INTO
phrases).  It is left unspecified whether bindings created with FOR or
AS clauses are available.  In most Common Lisps I am familiar with,
they are, but clisp is justified by the standard in not having them be
available.

This issue was discussed at length on the X3J13 mailing list as
LOOP-FOR-AS-VARIABLE-TERMINATION-VALUE.  I don't have my archives
handy, but I recall that the debate centered on problems with
arithmetic values being stepped past their ranges.

To get around the problem, you'd have to do something like:

(loop for char across fmt
      do
      (incf skip)
      (case char
	    (#\@ (setf at t))
	    (#\: (setf colon t)))
      until (and (operatorp char)
		 (setf cmd char)))

Ugly, but those are the breaks.

	    (for i from 1 to 10...

   example from Steele.

X3J13 "solved" the problem by changing the examples in the standard
that have FOR/AS bound variables referred to in FINALLY clauses so that
they didn't anymore.

Great title for a course:  "Programming as Archaeology."

--David Gadbois

---

From: "David J. Fiander" <[email-masked]>
Date: Wed, 12 Apr 1995 13:19:00 -0400

> Ugly, but those are the breaks.

Interestingly enough, that's exactly what I did, until I decided
to rewrite the whole function.  I now use a do* form.

> Great title for a course:  "Programming as Archaeology."

Hey!  That's an integral part of my job.  It's why I have POSIX,
SysVR3, BSD 4.3 and 4.4, and V7 manuals on my shell at work.

- David