[gambit-list] Syntax-case
Will Farr
farr at mit.edu
Tue Feb 12 12:34:08 EST 2008
Just a quick note about a pet-peeve of mine regarding define-macro:
> The disadvantages of define-macro:
>
> * with define-macro you have to care about hygiene yourself (e.g. you
> have to use (gensym) to introduce new identifyers into the transformed
> code, and you have to fully qualify symbols that you want to refer to a
> particular package instead of to the identifyers in the package of the
> user of the macro)
It's worse than this. Consider the following example:
(define-macro (do-times i-and-n . body)
(let ((i (car i-and-n))
(nn (cdr i-and-n))
(n (gensym)))
`(let ((,n ,nn))
(do ((,i 0 (+ ,i 1)))
((= ,i ,n))
, at body))))
(define v (vector 1 2 3 4 5 6 7 8 9 10))
(define v-of-v (vector v v v v v v v v v))
;; This works
(do-times (i 10)
(if (not (= (vector-ref v i) (+ i 1)))
(display "not equal")
(display "equal"))
(newline))
;; This barfs, because we've *locally* bound "=" (pretend we've
suitably defined vector=)
;; The error will be something like "vector=: expected <vector> got
1", coming from
;; the use of '= in the do test the macro expands into.
(let ((= vector=))
(do-times (i 10)
(if (not (= (vector-ref v-of-v i) v))
(display "not equal")
(display "equal"))
(newline)))
I've been bit by this bug before myself, in real code. And *there's
nothing you can do about it* using define-macro. It's *far* worse
than having to define a new gensym each time you want to introduce a
local variable. If you want to use define-macro, *don't ever*
re-define *any* standard symbol (even locally) if you want to be sure
that you're not hosing macros. Syntax-case/rules just does the right
thing here---and saves you from a very hard-to-find class of bugs.
Will
More information about the Gambit-list
mailing list