How to instantiate a Stream.Builder class in clojure? (using java 9) - clojure

I'm following this example to initiate a Stream.Builder:
http://www.java2s.com/Tutorials/Java/java.util.stream/Stream.Builder/Stream.Builder.build_.htm
(def b (doto (Stream/builder)
(.accept "a")
(.accept "b")
(.accept "c")
(.accept "d")
(.accept "e")))
However, I'm getting this:
Unhandled java.lang.IncompatibleClassChangeError
Method
java.util.stream.Stream.builder()Ljava/util/stream/Stream$Builder;
must be InterfaceMethodref constant
Is there anything I'm missing?

quick research led me to this issue:
https://dev.clojure.org/jira/browse/CLJ-2284
so the workaround is as mentioned there:
(import 'java.util.stream.Stream)
(defmacro interface-static-call
[sym & argtypes]
`(let [m# (.getMethod ~(symbol (namespace sym))
~(name sym)
(into-array Class ~argtypes))]
(fn [& args#]
(.invoke m# nil (to-array args#)))))
(doto ((interface-static-call Stream/builder))
(.accept "a")
(.accept "b")
(.accept "c")
(.accept "d")
(.accept "e"))
;;=> #object[java.util.stream.Streams$StreamBuilderImpl 0x121300ed "java.util.stream.Streams$StreamBuilderImpl#121300ed"]
works for me on java 9
so i guess we should wait for a fix in clojure.

Very helpful, thanks, for those of us stuck on Clojure 8 but needing to use a Java newer than 1.8.
For what it's worth, the macro in the answer above won't work if argtypes is not empty, because the macro as written constructs an unquoted list of classes as the third parameter to .getMethod, and Clojure tries to invoke the first class in the list as an IFn. I needed to redefine the macro as:
(defmacro interface-static-call
[sym & argtypes]
`(let [m# (.getMethod ~(symbol (namespace sym))
~(name sym)
(into-array Class ~(into [] argtypes)))]
(fn [& args#]
(.invoke m# nil (to-array args#)))))

Related

Trouble with using defmulti dispatch function

I have written this multi function in clojure.
(defmulti printlmt (fn [s] (> (count s) 10)))
(defmethod printlmt true [s] (println s))
(defmethod printlmt false [s] (println (take 10 s)))
I then try to execute it as below..
(printlmt "test")
But, I keep getting the following error.
IllegalArgumentException No method in multimethod 'printlmt' for dispatch value: 4 clojure.lang.MultiFn.getFn (MultiFn.java:156)
In my understanding the anonymous function should return a value of true. Why is the anonymous function returning 4?
If I call the dispatch function separately, like this
((fn [s] (> (count s) 0)) "test")
In this case it returns true!
Edit:
I'm adding the terminal text which I have:
startingclojure.core=> (defmulti printlmt (fn [s] (> (count s) 10)))
nil
startingclojure.core=> (defmethod printlmt true [s] (println s))
#object[clojure.lang.MultiFn 0x3315fe88 "clojure.lang.MultiFn#3315fe88"]
startingclojure.core=> (defmethod printlmt false [s] (println (take 10 s)))
#object[clojure.lang.MultiFn 0x3315fe88 "clojure.lang.MultiFn#3315fe88"]
startingclojure.core=>
startingclojure.core=> (printlmt "test")
IllegalArgumentException No method in multimethod 'printlmt' for dispatch value: 4 clojure.lang.MultiFn.getFn (MultiFn.java:156)
startingclojure.core=>
If you don't want to restart your repl for redefining a method, use remove-method
https://clojuredocs.org/clojure.core/remove-method
(remove-method printlmt true)
then redefine.
EDIT
You can use
(ns-unmap *ns* 'printlmt)
note: ns-unmap will require redefining all your methods as well.

How can I convert a Clojure namespace to a string?

I'm trying to pretty print a list of namespaces:
(doseq [x (all-ns)] (println x))
This prints each namespace as #<Namespace xxxxx>. I would like to get each namespace as xxxxx (that is without the #<Namespace>. I tried to (name x), (symbol x) but I get ClassCastException clojure.lang.Namespace cannnot be cast to java.lang.Named, etc.
(doseq [x (all-ns)] (println (name x)))
(doseq [x (all-ns)] (println (str x)))
(doseq [x (all-ns)] (println (namespace x)))
How can I get the namespace as a string?
Use ns-name:
(doseq [x (all-ns)] (println (ns-name x)))
Note that ns-name gives you a symbol. So if you want a string just use (str (ns-name ns)).
Use the ns-name function:
(doseq [x (all-ns)] (println (ns-name x)))
Namespace function docs can be found here
Best of luck.

Macro quoting and unquoting

I'm trying to write a macro to require some namespaces programmatically, so that the result for a passed-in argument would be (require 'value-of-argument). If I say (defmacro r [x] `(require ~x)) then I get (require value-of-x) as expected, but I can't work out how to get the quote in there.
Edit: here's a simpler example of my problem:
(defmacro q [x] `(str ~x))
=> (map (fn [e] (q e)) (map symbol ["x" "y" "z"]))
=> ("x" "y" "z")
however,
(defmacro q [x] `(str '~x))
=> (map (fn [e] (q e)) (map symbol ["x" "y" "z"]))
=> ("e" "e" "e")
All you need is to quote the argument again, like this:
(defmacro r [x] `(require '~x))
It should do the trick.
EDIT: The above won't work since x isn't known at compile time, when the macro is expanded.
However, now that I think about it, why not just call require directly, without a macro?
This seems to work:
(require (symbol "clojure.walk"))
Does that help?
(defmacro r [x] `(require (quote ~x)))

Clojure: Defining a symbol in another namespace

Context
This is the contents of init.clj
(ns init)
(defn get-hotswap []
(filter #(= (ns-name %) 'hotswap) (all-ns)))
(let [x (get-hotswap)]
(let [old-ns *ns*]
(if (empty? x)
(do
(create-ns 'hotswap)
(in-ns 'hotswap)
(def global-kv-store (clojure.core/atom {}))
(in-ns (ns-name old-ns)))
(println "Found Hotswap"))))
Now. hotswap/global-kv-store does not exist, but init/global-kv-store does exist.
Question
How do I fix this? I want to be able to
create a new namespace hotswap
and then define a new variable global-kv-store in it
Thanks!
You can try this:
(if-not (find-ns 'hotswap)
(intern (create-ns 'hotswap) 'global-kv-store (atom {})))

clojure: adding a debug trace to every function in a namespace?

just started using log4j in one of my home-projects and I was just about to break out the mouse and cut-and-paste (trace (str "entering: " function-name)) into every function in a large module. then the voice of reason caught up and said "there has simply got to be a better way"... I can think of making a macro that wraps a whole block of functions and adds the traces to them or something like that? Any advice from the wise Stack-overflowing-clojurians?
No need for a macro:
(defn trace-ns
"ns should be a namespace object or a symbol."
[ns]
(doseq [s (keys (ns-interns ns))
:let [v (ns-resolve ns s)]
:when (and (ifn? #v) (-> v meta :macro not))]
(intern ns
(with-meta s {:traced true :untraced #v})
(let [f #v] (fn [& args]
(clojure.contrib.trace/trace (str "entering: " s))
(apply f args))))))
(defn untrace-ns [ns]
(doseq [s (keys (ns-interns ns))
:let [v (ns-resolve ns s)]
:when (:traced (meta v))]
(alter-meta! (intern ns s (:untraced (meta v)))
#(dissoc % :traced :untraced))))
...or something similar. The most likely extra requirement would be to use filter so as not to call trace on things which aren't ifn?s. Update: edited in a solution to that (also handling macros). Update 2: fixed some major bugs. Update 4: added untrace functionality.
Update 3: Here's an example from my REPL:
user> (ns foo)
nil
foo> (defn foo [x] x)
#'foo/foo
foo> (defmacro bar [x] x)
#'foo/bar
foo> (ns user)
nil
user> (trace-ns 'foo)
nil
user> (foo/foo :foo)
TRACE: "entering: foo"
:foo
user> (foo/bar :foo)
:foo
user> (untrace-ns 'foo)
nil
user> (foo/foo :foo)
:foo