

RE: macros vs. blocks

On Mon, 18 Nov 2002, Guy Steele - Sun Microsystems Labs wrote:

> Here's another macro that would be hard to do with just
> closures and reference parameters.  It's also reeeeally
> hard to do in C, because C doesn't have a very good
> representation for program fragments (just strings)
> and doesn't even have good ways for a macro to pick
> apart that representation.  So I'll have to conduct the
> example in Lisp only.
> The goal is to have something that looks like a function
> that takes a (numerical) function as an argument and finds
> its roots, or a root.  Something like this:
>  (findroots (lambda (a) (* (sin a) (+ a (* 3 a)))))


> What this is doing is tearing apart the lambda expression
> symbolically, computing a symbolic derivative, blindly using
> all the usual rules one learns in first-semester calculus.

Smalltalkers actually do use a closure-based trick to do similar things.
The best known example is the TopLink O/R mapping framework and its
derivatives, which allow you to use block notation to specify SQL queries
(the GoF Interpreter pattern is also similar).

So, you specify something like

table select:
  [:ea | (ea firstName = 'Avi') & (ea address city = 'Vancouver')]

and it will generate the appropiate SQL.  The trick is that what gets
passed into the block is not an actual row, but a proxy object that
responds to any message by creating an appropiate parse node for the
expression, and then returning another proxy.  In this way, the code
inside the block gets built into a parse tree at runtime, which can then
be used to perform symbolic differentiation, SQL generation, or whatever.

I think this as pretty (or prettier) a solution as using macros, and is
a good example of the ways in which different language features
(lightweight lambda syntax + message-based dispatch vs. macros) can come
up with different but equally elegant solutions to the same problem.  Note
that you couldn't easily do this in Scheme (because you can't add methods
to arithmetic functions, for example) or even in CLOS (because there's no
equivalent of Smalltalk's #doesNotUnderstand:).