4

How can I use java methods as a functions arguments in Clojure?

For example, I want to make a functions composition:

user> (Integer. (str \9))
9
user> ((comp Integer. str) \9)
CompilerException java.lang.ClassNotFoundException: Integer., compiling:(NO_SOURCE_PATH:1:2) 

That does not work.

memfn doesn't help also:

user> (map (comp (memfn  Integer.) str) "891")
IllegalArgumentException No matching method found: Integer. for class java.lang.String  clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:53)

Any ideas?

Related questions (that, though, do not give the right answer to the question):

(Note: it seems to be that the answer suggested by dave, using of an anonymous function as a wrapper, is the best solution)

Community
  • 1
  • 1
Igor Chubin
  • 61,765
  • 13
  • 122
  • 144

1 Answers1

6

Unlike Clojure functions, Java methods weren't designed to be first class. When you use Java inter-op in Clojure, you're literally working with Java methods, so you don't get the added benefits that were implemented for Clojure functions. For more info, see the comments below.

As a workaround to use Java methods as arguments, you can wrap them in an anonymous function, like this, effectively making them Clojure functions:

((comp #(Integer. %) str) \9)
Dave Yarwood
  • 2,866
  • 1
  • 17
  • 29
  • Dave, thank you, that is better than nothing, but I hope there are some other ways also (+1) – Igor Chubin Apr 16 '14 at 19:35
  • 2
    Why aren't methods Clojure functions? Clojure functions are Java *objects* that comply with the `IFn` interface, which has a pile of `invoke` methods of all arities up to twenty, and a couple of ways of invoking on indefinitely long argument lists. All of these take Java `Object` arguments and also return a Java `Object`. You can find `IFn` at https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/IFn.java – Thumbnail Apr 16 '14 at 19:45
  • 1
    They are not first class because as I see it the choices were either having functions that are not truly first class values (making the language weaker), or abstracting over all jvm method so they act like true functions (making the language excessively complex). – noisesmith Apr 16 '14 at 19:46
  • I'd be curious as well, to know why exactly you can't use Java methods as functions. I don't know much about Java, but my guess is that Java methods aren't first-class in Java, so Clojure added this functionality to its own functions, but when you use Java inter-op you're literally dealing with Java methods, so you don't get the added benefits that you get with Clojure functions. – Dave Yarwood Apr 16 '14 at 19:46
  • EDIT: Listen to @Thumbnail and noisesmith, they know what they're talking about! :) – Dave Yarwood Apr 16 '14 at 19:48
  • 2
    Exactly. Clojure keeps its interop layer as small and simple as possible, and methods simply are not meant to be first class. – noisesmith Apr 16 '14 at 19:48