souenzzo
souenzzo

Reputation: 428

Unquote a java method in clojure

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

Answers (4)

souenzzo
souenzzo

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

Arthur Ulfeldt
Arthur Ulfeldt

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

Alan Thompson
Alan Thompson

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

ClojureMostly
ClojureMostly

Reputation: 4713

Use memfn:

(def url (java.net.URL. "http://www.google.com"))
(def host (memfn getHost))
(host url)

Upvotes: -1

Related Questions