You are right that
(let [Object (fn [] 3)] (Object))
is valid Clojure code, and it works as expected. However,
(Object)
is not a valid expression. It fails with exactly the same error
message as
(macroexpand '(Object))
so I'd say this is consistent behaviour.
Konrad.
More annoying is the result this has on macroexpand-all, which breaks
because of this weird behaviour:
(use 'clojure.walk)
(walk/macroexpand-all '(let [Object (fn [])] (Object)))
java.lang.RuntimeException: java.lang.Exception: Expecting var, but
Object is mapped to class java.lang.Object (NO_SOURCE_FILE:0)
Of course, this example is somewhat (not super-) obvious, but in more
complex cases it could be fairly annoying.
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> If you were to say, (macroexpand '(foo)), it returns (foo), even if
> it's
> not defined in the context, so I'd say it's a little unexpected.
True, but then, the function macroexpand is mostly a development tool,
for which I can accept such minor issues. Macroexpansion itself is
part of the evaluation procedure of forms, so it makes no sense to
define what macroexpansion should return for a form that is not legal
code anyway. Neither (Object) nor (foo) are legal code.
> More annoying is the result this has on macroexpand-all, which breaks
> because of this weird behaviour:
>
> (use 'clojure.walk)
> (walk/macroexpand-all '(let [Object (fn [])] (Object)))
>
> java.lang.RuntimeException: java.lang.Exception: Expecting var, but
> Object is mapped to class java.lang.Object (NO_SOURCE_FILE:0)
Right, but then this should be blamed on macroexpand-all, which
implements a crude approximation to how macroexpansion is done by the
compiler.
There's also clojure.contrib.macro-utils/mexpand-all, which does a
much better job, but still fails for this particular example. In fact,
neither one tracks the lexical environment.
Konrad.
> Right, but then this should be blamed on macroexpand-all, which
> implements a crude approximation to how macroexpansion is done by
> the compiler.
>
> There's also clojure.contrib.macro-utils/mexpand-all, which does a
> much better job, but still fails for this particular example. In
> fact, neither one tracks the lexical environment.
clojure.contrib.macro-utils/mexpand-all now does track the lexical
environment. In fact, it already did before, but it used that
information only for symbol macro expansion.
Konrad.