Minor macroexpand issue

34 views
Skip to first unread message

Frederic Koehler

unread,
Aug 30, 2010, 5:18:30 PM8/30/10
to Clojure
I accidentally noticed this:

On clojure 1.2, macroexpanding with a function name which is a class,
causes this ugly error:

> (macroexpand '(Object))
java.lang.Exception: Expecting var, but Object is mapped to class
java.lang.Object (repl-1:2)

when presumably it should just give '(Object).
I have no clue for any actual use cases of naming your functions after
classes, but:
(let [Object (fn [] 3)] (Object))
is technically valid clojure code, so macroexpand shouldn't just die...

Konrad Hinsen

unread,
Aug 31, 2010, 2:14:49 AM8/31/10
to clo...@googlegroups.com

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.

Frederic Koehler

unread,
Aug 31, 2010, 6:17:18 PM8/31/10
to clo...@googlegroups.com
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.

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


Armando Blancas

unread,
Aug 31, 2010, 8:33:11 PM8/31/10
to Clojure
I agree, that's not the expected behavior. The form is just data, it
doesn't have to be valid code. Since '(Object) is not a macro (Object
is a Symbol there, not a class) it should just return the form just
like (identity) does:
user=> (identity '(Object))
(Object)

But macroexpand-1 does some extra work for the interop sugar. I
suspect that the error comes when it tries to work out a static
member.

user=> (macroexpand-1 '(.length "s"))
(. "s" length)
user=> (macroexpand-1 '(Boolean/TRUE))
(. Boolean TRUE)
user=> (macroexpand-1 '(String.))
(new String)
> >http://groups.google.com/group/clojure?hl=en- Hide quoted text -
>
> - Show quoted text -

Konrad Hinsen

unread,
Sep 1, 2010, 2:25:38 AM9/1/10
to clo...@googlegroups.com
On 1 Sep 2010, at 00:17, Frederic Koehler wrote:

> 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.

Konrad Hinsen

unread,
Sep 3, 2010, 3:42:43 PM9/3/10
to clo...@googlegroups.com
On 1 Sep 2010, at 08:25, Konrad Hinsen wrote:

> 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.

Reply all
Reply to author
Forward
0 new messages