Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!usc!elroy.jpl.nasa.gov!decwrl!pa.dec.com!src.dec.com!meehan From: meehan@src.dec.com (Jim Meehan) Newsgroups: comp.lang.lisp Subject: Re: macro misbehaviour Message-ID: <1991Jun9.215315.25797@src.dec.com> Date: 10 Jun 91 04:53:15 GMT Sender: news@src.dec.com (News) Organization: DEC Systems Research Center Lines: 65 In-Reply-To: Message of 10 Jun 91 02:38:59 GMT from gt4084c@prism.gatech.EDU (SRINIVASAN,K) <16456.285261a2@levels.sait.edu.au> Originator: meehan@srcf2b.pa.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.