[racket] Again on bindings visibility in eval

From: Stephan Houben (stephanh at planet.nl)
Date: Fri Jul 15 04:00:46 EDT 2011

On 07/15/2011 05:40 AM, Mark Engelberg wrote:
> I would like to better understand how Clojure's mitigation strategy is
> insufficient.  Since Eli's document is all about the while macro,
> let's look at Clojure's while macro.
>
> (defmacro while [test&  body]
>    `(loop []
>       (when ~test
>         ~@body
>         (recur))))
>

This doesn't work at the REPL as such since clojure.core/while cannot be
redefined (unlike in Racket) but let's assume you typed my-while or
went through the namespace magic to have while refer to something you can change.

> What is broken about this?  I tried breaking it in a way comparable to
> what Eli did in his document, e.g., binding every keyword/variable in
> the macro to something non-sensical, but it didn't break.  Here's the
> comparable Clojure code to what Eli did:
> (def x (atom 2))
> (let [loop 5 when 2 test 4 body 3 recur 4]
>             (while (<  @x 10)
>               (println @x)
>               (reset! x (inc @x))))

Quasi-quote is magical in Clojure and replaces symbols in the pattern by
their equivalents in the global namespace.
Compare:

user=> `while
clojure.core/while
user=> 'while
while

So the macro is probably fine as-is, but this relies
on you having stayed within the confines of the quasi-quote sublanguage.

As soon as you start manipulating code using quote and cons you run back
in all the usual issues.

BTW, this "feature" appears to be quite undocumented, I found it
out by experimentation.
So it is anybody's guess what happens if you have macro-expanders calling
functions in different namespaces which use quasiquote, or even macros
which expand into macros with multiple levels of quasi-quote.

Stephan


Posted on the users mailing list.