> If you really don't know what the class is (for example, you get a
> Class object returned by some library function) then you can use the
> Java Reflection API to call the static method. See
> http://java.sun.com/docs/books/tutorial/reflect/
If you go this route, I recommend either using or learning from the
functions in clojure/src/jvm/clojure/lang/Reflector.java. Its methods
are not part of Clojure's official interface, so the usual caveats
about using unsupported "implementation private" code apply, but it
include many useful methods for dealing with reflection from Clojure.
--Steve
Lets say you want to call static method "foo" of a class,
but you don't know which class -- you want this to be
specified at runtime in a parameter. Something like this:
(defn map-foo [cls coll]
(map cls/foo coll)) ; doesn't work
As mentioned by others, one approach is to use reflection,
either Java's API or Clojure's (undocumented,
may-change-without-warning) wrapper:
(defn map-foo [cls coll]
(map #(clojure.lang.Reflector/invokeStaticMethod
cls "foo" (to-array [%]))
coll))
(map-foo MyClass [1 2 3 4])
This works, but if you're allowed to adjust the requirements
a bit, a better solution is possible. What if your user
called:
(map-foo #(MyClass/foo %) [1 2 3 4])
This can be done without any runtime reflection at all,
which can greatly boost the runtime speed. Also, it's more
flexible: I *told* you to name your method "foo" but
I guess I should have been more explicit. Oh well, no
matter:
(map-foo #(YourClass/Foo %) [1 2 3 4])
Or if your user is using Clojure rather than Java, they
don't even have to use a class:
(map-foo #(her-do-foo-thing %) [1 2 3 4])
or just:
(map-foo her-do-foo-thing [1 2 3 4])
Best of all implementing map-foo is simpler:
(defn map-foo [f coll]
(map f coll))
Which in this trivial example means you can just use 'map'
instead of 'map-foo'. But even in a less trivial example
you may find this approach more workable all around.
Now if you were going to do more than one thing on the class
(call static methods foo, bar, and baz, for example) things
get more complicated. You may be able to pass around a map
of fns, perhaps assisted by a macro. ...or you may decide
that reflection is better after all.
(map-things {:foo #(MyClass/foo %)
:bar #(MyClass/bar %)
:baz #(MyClass/baz %)}
coll)
(map-things (static-method-map MyClass [foo bar baz]) coll)
--Chouser