[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Parodies make everyone mad
On Mon, 2002-11-18 at 13:31, Scott McKay wrote:
> This begs the question, what are a reasonable set of guidelines
> for writing good macros in a language like Lisp or Scheme. Here
> are some rules of thumb I use; I'm embarrassed to write this
> because the shortness of the list and the lack of rigor shows
> the lack of depth in my thinking in this area. I hope that
> people who've thought more deeply and thoroughly will use this
> as an excuse to write down a good list.
Well, I won't make any claims to having thought about these issues more
thoroughly than Scott McCay, but I'll chip in my two cents.
1) Before writing a macro, create the best non-macro interface you
can for the feature in question, then wrap a macro around it.
This makes your macro much easier to write, and it allows you
to access the underlying API in a more dynamic fashion if the
need arises. ("Oh, what a nice set of GUI macros! But I want
read my widget layouts from an XML file. Drat.")
2) Write small macros if they'd make your code cleaner. ("Small",
for the sake of discussion, means "anything you can do with
syntax-rules and ten lines of code.") If you follow rule (1)--
and your macros are small enough--then your macros will be
nearly as easy to grok as functions. Even novice programmers
can learn to do this right.
3) Write big macros only under extreme provocation. Big macros
are dense, hard to maintain, and do alarming things to your
language. They're also invaluable, but you wouldn't want more
than 10 of them per mid-sized company, or you'd go mad. Even
experts tend to make a pig's breakfast of big macros, so
plan for extensive peer review. And document each of them in
your site's coding guidelines, OK? (If you're Paul Graham,
etc., certain exceptions may apply.)
Rules (2) and (3) are interesting--they suggest that there are two kinds
of macros. I think is mirrored, to a certain extent, in Scheme's API,
where SYNTAX-RULES is (mostly) useful for defining small, inoffensive
macros and Chez Scheme's SYNTAX-CASE is (mostly) useful for defining
large, powerful, hard-to-maintain macros.
Neel's proposal to implement macros using an (object-oriented?) parse
tree interface is interesting here. Combined with something like
SYNTAX-RULES, it would make the simple macros easy, and the hard macros
sufficiently difficult to scare away anyone without solid skills and a
pressing need. ;-)
4) Hygiene is good, because it allows you to preserve source
location information and feed it to your IDE and debugger.
Yes, SYNTAX-CASE is harder to use than LISP's
DEFMACRO. But doesn't DrScheme give such *nice* error
messages when you use SYNTAX-CASE? And isn't the automatic,
accurate syntax highlighting pretty?
5) Do not release a language (a) with macros and (b) without
classes. This will result in 60 incompatible macro
libraries for implementing classes. (The same goes for
C++'s mysterious lack of a 'string' class until the STL
appeared.) If you have macros, make sure your language
also includes all the constructs necessary for normal,
modern programming styles.
6) Do not, under any circumstance, write a LOOP or FOR macro
that takes more than two pages of code to implement. Nobody
understands all the frobs and gadgets in Common LISP's LOOP,
and few people use more than a third of Dylan's FOR macro.
("Oooh, in what order should we evaluate the test-clauses
if we include *both* a frob-clause *and* a gadget-clause?")
Adding massive amounts of chrome to core language features
is pure self-indulgence.