Clojure vars and Java static methods
- by j-g-faustus
I'm a few days into learning Clojure and are having some teething problems, so I'm asking for advice.
I'm trying to store a Java class in a Clojure var and call its static methods, but it doesn't work.
Example:
user=> (. java.lang.reflect.Modifier isPrivate 1)
false
user=> (def jmod java.lang.reflect.Modifier)
#'user/jmod
user=> (. jmod isPrivate 1)
java.lang.IllegalArgumentException: No matching method found: isPrivate for class java.lang.Class (NO_SOURCE_FILE:0)
at clojure.lang.Compiler.eval(Compiler.java:4543)
From the exception it looks like the runtime expects a var to hold an object, so it calls .getClass() to get the class and looks up the method using reflection. In this case the var already holds a class, so .getClass() returns java.lang.Class and the method lookup obviously fails.
Is there some way around this, other than writing my own macro?
In the general case I'd like to have either an object or a class in a varible and call the appropriate methods on it - duck typing for static methods as well as for instance methods.
In this specific case I'd just like a shorter name for java.lang.reflect.Modifier, an alias if you wish. I know about import, but looking for something more general, like the Clojure namespace alias but for Java classes. Are there other mechanisms for doing this?
Edit:
Maybe I'm just confused about the calling conventions here. I thought the Lisp (and by extension Clojure) model was to evaluate all arguments and call the first element in the list as a function.
In this case (= jmod java.lang.reflect.Modifier) returns true, and (.getName jmod) and (.getName java.lang.reflect.Modifier) both return the same string.
So the variable and the class name clearly evaluate to the same thing, but they still cannot be called in the same fashion. What's going on here?
Edit 2
Answering my second question (what is happening here), the Clojure doc says that
If the first operand is a symbol that
resolves to a class name, the access
is considered to be to a static member
of the named class... Otherwise it is
presumed to be an instance member
http://clojure.org/java_interop under "The Dot special form"
"Resolving to a class name" is apparently not the same as "evaluating to something that resolves to a class name", so what I am trying to do here is something the dot special form does not support.