Reputation: 428
How do I parameterize calls methods in Clojure?
Example:
(def url (java.net.URL. "http://www.google.com"))
(.getHost url) ;; works!
(def host '.getHost)
(host url) ;; Nope :(
(~host url) ;; Nope :(
(eval `(~host url)) ;; Works :s
Upvotes: 1
Views: 228
Reputation: 428
Right solution (updated clojure 1.12):
(def url (java.net.URL. "http://www.google.com"))
(def host java.net.URL/.getHost)
(host url)
=> "www.google.com"
;; old//fully dynamic version
(def host-sym 'getHost)
(defn dynamic-invoke
[obj method & arglist]
(.invoke (.getDeclaredMethod
(class obj) (name method) nil)
obj (into-array arglist)))
(dynamic-invoke url host-sym)
Upvotes: 1
Reputation: 91587
The normal way to parametrize a method on a Java class is:
#(.method fixed-object %)
or
#(.method % fixed argument)
or if neither the object or the arguments are fixed.
#(.method %1 %2)
Often used with higher order functions line map, filter and reduce.
(map #(.getMoney %) customers)
Upvotes: 0
Reputation: 29974
If you simply want to create an alias for an existing function, a wrapper function is all you need:
> (ns clj (:import [java.net URL]))
> (def url (URL. "http://www.google.com"))
> (defn host [arg] (.getHost arg))
> (host url)
;=> "www.google.com"
While you could use memfn
as pointed out by another user, it seems less obvious what is going on. Indeed, even clojure.org recommends against it now:
https://clojure.org/reference/java_interop
(memfn method-name arg-names)*
Macro. Expands into code that creates a fn that expects to be passed an object and any args and calls the named instance method on the object passing the args. Use when you want to treat a Java method as a first-class fn.
(map (memfn charAt i) ["fred" "ethel" "lucy"] [1 2 3])
-> (\r \h \y)
Note it almost always preferable to do this directly now, with syntax like:
(map #(.charAt %1 %2) ["fred" "ethel" "lucy"] [1 2 3])
-> (\r \h \y)
Upvotes: 0
Reputation: 4713
Use memfn
:
(def url (java.net.URL. "http://www.google.com"))
(def host (memfn getHost))
(host url)
Upvotes: -1