I apologize in advance for the length of this post, but I need to
start with an example before my question will make sense.

I have been looking at the inner workings of Clojure's Java interop,
and I wondered how it would handle classes with a field and method
with the same name, like this:

public class InteropTest {
    public String str = "Field";
    public String str() { return "0-arg Method"; }
}

Granted, duplicating names like this is bad practice, but Java allows
this and Clojure should provide access to both the field and the
method.

Using Clojure compiled from a git master snapshot today, I first
create an instance of InteropTest:
   Clojure 1.2.0-master-SNAPSHOT
   user=> (import InteropTest)
   InteropTest
   user=> (def x (InteropTest.))
   #'user/x

As noted in the docs, access to str resolves to the 0-arg method:
   user=> (.str x)
  "0-arg Method"

But I see in Compiler.java that the field can still be accessed by
using a keyword instead of a symbol:
   user=> (. x :str)
   "0-arg Method"
   user=> (. ^InteropTest x :str)
   "Field"

This only seems to work when the type hint is included.  However, the
value of this field access expression depends on how it is used.  It
doesn't work with def:
   user=> (def field (. ^InteropTest x :str))
   #'user/field
   user=> field
   "0-arg Method"

It does work as a function argument:
   user=> (defn okay [x] x)
   #'user/okay
   user=> (okay (. ^InteropTest x :str))
   "Field"

...unless the function name happens to start with "def":
   user=> (defn defective [x] x)
   #'user/defective
   user=> (defective (. ^InteropTest x :str))
   "0-arg Method"

The reason for this perplexing behavior is Clojure's
clojure.lang.Compiler#analyze method, which is part of the evaluation
process.  Given an expression list expr, this method wraps it with
(fn* [] expr), compiles it (indirectly calling expr.emit()), then runs
it; however, if the first form in the list is a symbol that starts
with "def", it instead calls expr.eval().

So with that long-winded introduction out of the way, here's my
question: why is eval needed?  Looking through the expression types in
Compiler.java, I see some expression classes (including
InstanceFieldExpr and InstanceMethodExpr, which handle field access
and method invocation) that appear to have subtle differences between
the emit() and eval() methods.  Apart from my example above, I
couldn't find any other actual expressions with differing results, but
I wonder if there are others.  If eval() could be eliminated, this
problem wouldn't happen.

- Spencer

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to