[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