2009-01-03

On the order of macro expansions

Just a moment ago, I was able to dig out a definitive answer for an old question of mine: Can one expect macros to be expanded in the order they textually appear in a source file?

Answer: No, you cannot.

The expectation originated in Common Lisp's evaluation model (CLHS 3.1.2) which can be described to be basically top-down, left-to-right (CLHS 3.1.2.1.2.3).

That expectation was short-sighted, though, as processing and evaluating are two differen things. And, indeed, item #6 in CLHS 3.2.3.1 specifies:
Note that top level forms are processed in the order in which they textually appear in the file and that each top level form read by the compiler is processed before the next is read. However, the order of processing (including macro expansion) of subforms that are not top level forms and the order of further compilation is unspecified as long as Common Lisp semantics are preserved.
Which makes perfect sense as it allows compilers to do transformations on the Lisp source code before or along macroexpansion.

For example, UNWIND-PROTECT could be a macro turning
(unwind-protect (protected-form)
  (cleanup-form1)
  (cleanup-form2))
into
(let ((cleanup-thunk #'(lambda () (cleanup-form1) (cleanup-form2))))
  (declare (dynamic-extent cleanup-thunk))
  (%establish-unwind-guard cleanup-thunk)
  (protected-form)
  (funcall cleanup-thunk) ; no unwinding happened
  (%remove-unwind-guard))

2 comments:

nuntius said...

Would something like the following work?

(defmacro bother-tcr (&body forms)
  (let ((result nil))
    (dolist (item (reverse forms))
      (push (macroexpand item) result))
    result))

Movies Gallery 2011 said...

Thanks for the experiment. Keep posting. It was very useful.
Angry Birds Clone| Money Talks|