Copyright © 2003-2005, Peter Seibel
7. Macros: Standard Control Constructs
While many of the ideas that originated in Lisp, from the conditional expression to garbage collection, have been incorporated into other languages, the one language feature that continues to set Common Lisp apart is its macro system. Unfortunately, the word macro describes a lot of things in computing to which Common Lisp’s macros bear only a vague and metaphorical similarity. This causes no end of misunderstanding when Lispers try to explain to non-Lispers what a great feature macros are.1 To understand Lisp’s macros, you really need to come at them fresh, without preconceptions based on other things that also happen to be called macros. So let’s start our discussion of Lisp’s macros by taking a step back and looking at various ways languages support extensibility.
All programmers should be used to the idea that the definition of a language can include a standard library of functionality that’s implemented in terms of the “core” language—functionality that could have been implemented by any programmer on top of the language if it hadn’t been defined as part of the standard library. C’s standard library, for instance, can be implemented almost entirely in portable C. Similarly, most of the ever-growing set of classes and interfaces that ship with Java’s standard Java Development Kit (JDK) are written in “pure” Java.
One advantage of defining languages in terms of a core plus a standard library is it makes them easier to understand and implement. But the real benefit is in terms of expressiveness—since much of what you think of as “the language” is really just a library—the language is easy to extend. If C doesn’t have a function to do some thing or another that you need, you can write that function, and now you have a slightly richer version of C. Similarly, in a language such as Java or Smalltalk where almost all the interesting parts of the “language” are defined in terms of classes, by defining new classes you extend the language, making it more suited for writing programs to do whatever it is you’re trying to do.
While Common Lisp supports both these methods of extending the language, macros give Common Lisp yet another way. As I discussed briefly in Chapter 4, each macro defines its own syntax, determining how the s-expressions it’s passed are turned into Lisp forms. With macros as part of the core language it’s possible to build new syntax—control constructs such as **WHEN**
, **DOLIST**
, and **LOOP**
as well as definitional forms such as **DEFUN**
and **DEFPARAMETER**
--as part of the “standard library” rather than having to hardwire them into the core. This has implications for how the language itself is implemented, but as a Lisp programmer you’ll care more that it gives you another way to extend the language, making it a better language for expressing solutions to your particular programming problems.
Now, it may seem that the benefits of having another way to extend the language would be easy to recognize. But for some reason a lot of folks who haven’t actually used Lisp macros—folks who think nothing of spending their days creating new functional abstractions or defining hierarchies of classes to solve their programming problems—get spooked by the idea of being able to define new syntactic abstractions. The most common cause of macrophobia seems to be bad experiences with other “macro” systems. Simple fear of the unknown no doubt plays a role, too. To avoid triggering any macrophobic reactions, I’ll ease into the subject by discussing several of the standard control-construct macros defined by Common Lisp. These are some of the things that, if Lisp didn’t have macros, would have to be built into the language core. When you use them, you don’t have to care that they’re implemented as macros, but they provide a good example of some of the things you can do with macros.2 In the next chapter, I’ll show you how you can define your own macros.