From: Jim Meehan
Subject: Re: macro misbehaviour
Date: 
Message-ID: <1991Jun9.215315.25797@src.dec.com>
    I wrote the following macro for reading a file and defining classes.
    During any single iteration, the three calls to "read" read three
    succesive symbols from the file as you would expect.  However,
    during successive iterations, the same set of three symbols are
    read repeatedly.  So, I get the same class defined 4 times instead
    of defining 4 different classes.  If I put in 4 explicit calls
    contained in a progn form instead of the do-loop, it works fine.
    Can somebody please help me fix this

    (defmacro class-from-file (file-name)
      (with-open-file (input-stream file-name
    				:direction :input)
        `(do ((q 4 (- q 1))) ((= q 0) nil)
          (Define-Class ,(read input-stream) ,(read input-stream)
                        .,(read input-stream)))))

The immediate problem is that there is only one set of 3 calls to READ
at macroexpansion time.  The loop iterates at runtime, not at
macroexpansion time.  To produce the effect you want, you'd have to
say something like this:

(defmacro class-from-file (file-name)
  (with-open-file (input-stream file-name)
    (do ((q 4 (- q 1))
         (code '()
               (cons `(Define-Class ,(read input-stream)
                                    ,(read input-stream)
                                    .,(read input-stream))
                     code)))
        ((= q 0) `(progn ,@(nreverse code))))))

[Are you sure about that ".," ?]

More generally, it is a BAD idea to write macros that have side-effects
like this. (An earlier example with EVAL was similarly afflicted.)

1. Macros are best thought of as shorthand, where the expansion is
entirely equivalent to the unexpanded form, in the sense in which
(cadr (baz)) is equivalent to (car (cdr (baz))).  Lots of software
tools ("code-walkers") may be interested in expanding macros.  The
compiler is one.  If you wrote (class-from-file "FOO") in a program
that you compiled, it would have opened the file and read the symbols
in the process of compiling.  A prettyprinter or a debugger might also
expand a macro; you probably don't want them opening the file.  If you
had looked at the expansion of the macro, e.g., via
    (macroexpand '(class-from file "FOO"))
you would have noticed that (A) the expander opened the file, and (B)
the expansion was incorrect.

2. You're using a macro only because you're trying to "call" another macro;
if Define-Class were a function, then class-from-file would be a
function, and you wouldn't have had a problem.

It may be that the macro (Define-Class x y z) expands into something
simple like (*Define-Class 'x 'y 'z), where *Define-Class is a function
that actually does all the work.  If that's the case, then you should
rewrite class-from-file as a function that calls *Define-Class 4 times:
no muss, no fuss, no backquotes.

If that's not an option, then you may want to define a separate "pass"
in which you make all your calls to class-from-file and similar
macro-calling macros, because that pass is *generating* Lisp code.
If you've ever used the C tools yacc and lex, you'll understand what
I mean.
From: Barry Margolin
Subject: Re: macro misbehaviour
Date: 
Message-ID: <1991Jun11.035518.11535@Think.COM>
In article <·····················@src.dec.com> ······@src.dec.com (Jim Meehan) writes:
>2. You're using a macro only because you're trying to "call" another macro;
...
>It may be that the macro (Define-Class x y z) expands into something
>simple like (*Define-Class 'x 'y 'z), where *Define-Class is a function
...
>If that's not an option, then you may want to define a separate "pass"
>in which you make all your calls to class-from-file

Actually, solving the problem of trying to "call" a macro is one of the few
excuses for using EVAL.

CLASS-FROM-FILE could be a function (*not* a macro) that looks something
like this:

(defun class-from-file (file-name)
  (with-open-file (input-stream file-name :direction :input)
    (dotimes (q 4)
      (eval `(define-class ,(read input-stream) ,(read input-stream)
		.,(read input-stream))))))
-- 
Barry Margolin, Thinking Machines Corp.

······@think.com
{uunet,harvard}!think!barmar