This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-11-04
Channels
- # announcements (4)
- # babashka (15)
- # beginners (147)
- # bristol-clojurians (8)
- # calva (6)
- # chlorine-clover (39)
- # clj-kondo (29)
- # clojure (95)
- # clojure-australia (1)
- # clojure-berlin (1)
- # clojure-europe (24)
- # clojure-nl (3)
- # clojure-spec (185)
- # clojure-uk (98)
- # clojured (2)
- # conjure (3)
- # core-async (26)
- # datomic (11)
- # etaoin (1)
- # events (1)
- # fulcro (26)
- # graalvm (3)
- # graphql (4)
- # jobs (7)
- # jobs-discuss (1)
- # kaocha (12)
- # leiningen (21)
- # malli (2)
- # meander (2)
- # parinfer (3)
- # pathom (3)
- # pedestal (5)
- # remote-jobs (2)
- # shadow-cljs (71)
- # spacemacs (2)
- # sql (4)
- # tools-deps (22)
- # tree-sitter (1)
- # vim (2)
- # xtdb (5)
I'm going to give a (remote) introduction of clojure for some coworkers. I'll check the popular plugins for their editors (mostly vscode I think), but some of them are non-programmers. For them, I'm looking into the easiest to setup clojure ide. Maybe even something on cloud. I looked into http://repl.it but it doesn't allow to eval a single expression, only the whole file, and that seems so limiting when it comes to lisps.
Why not just use default repl for non-programmers? Which features of IDE you want to use? IMHO, just using the plain repl will make things easier in terms of tooling and setup issues.
BTW I've tried cursive and I'm currently using vscode(with calva and clj-kondo). vscode feels easier for me.
Using the repl directly is something that I didn't even think of doing, but actually makes sense, specially at the beginning. It's a good way to make them understand that the ide isn't doing much more than the line you're evaluating to the repl.
But it's quite limiting, and not really a fun way to program, IMO. My main goal is to have them continue coming to the clojure lessons 😅
IMHO, it'd be better to do a quick intro to vscode + calva, at least to show how to set it up and then proceed to clojure. Hmm.. before vscode you can also do a quick intro to the plain repl itself, then say that there are much better tools for clojure dev and then show them vscode. You'll figure it out 🙂

- I think there's a way to connect jupyter notebooks with Clojure - Reveal might make the experience more pleasant for them
Once leinigen or clj is installed, Calva is for sure a pretty easy step. But for people who aren’t devs, getting Java and lein installed can be quite daunting…
That is true... I've also never installed clojure outside of Linux, and it's remote so hard to help. I'm actually considering using babashka instead.
Thanks for the suggestions. I'm an emacs user, so I'll install vscode + calva by myself to see how easy it is and if I can guide people through it.
I was thinking if babashka might be the way to go. I've been wanting to bundle it with Calva. That would remove so much friction towards just trying the language out. Anyway, if you use babashka, what you need to do is to start it with its nrepl option and then connect Calva. When is this intro to happen?
It's still not decided, could be in a week or in a month. I actually just got news two hours ago that I'm allowed to fly back to Singapore, where my work is located. This would mean I could do it in person, in small groups of 5 people max (covid is under pretty good control there).
Java interrop question.. How can I call .drainTo
in Clojure on a BlockingQueue?
Attempt below:
(import '[java.util.concurrent LinkedBlockingQueue BlockingQueue]
'[java.util ArrayList])
(let [^BlockingQueue q (doto (LinkedBlockingQueue.)
(.put [:command 1])
(.put [:command 2])
(.put [:command 3]))
coll (ArrayList.)]
;;
;; drainTo(Collection<? super E> c)
;; Removes all available elements from this queue and adds them to the given collection.
(.drainTo coll)
;; FAIL
;; Unhandled java.lang.IllegalArgumentException
;; No matching field found: drainTo for class java.util.ArrayList
;; FAIL
;; (.drainTo (make-array (type []) 3))
;; Unhandled java.lang.IllegalArgumentException
;; No matching field found: drainTo for class [Lclojure.lang.PersistentVector;
coll)
That should be (.drainTo q coll)
, I think. See also https://clojure.org/reference/java_interop
This might be an unimportant performance thing, but why isn't destructure using find
+ val
here:
https://github.com/clojure/clojure/blob/7baa5b2f79f05c56a04e1d5c90129972cd962df3/src/clj/clojure/core.clj#L4465-L4466
user=> (let [defaults {:a 1}] (time (dotimes [i 100000000] (val (find defaults :a)))))
"Elapsed time: 379.921527 msecs"
nil
user=> (let [defaults {:a 1}] (time (dotimes [i 100000000] (contains? defaults :a) (defaults :a))))
"Elapsed time: 759.108181 msecs"
feel free to file a jira
wow. crazy how different the speeds of (defaults :a)
(:a defaults)
and (get defaults :a)
are
Actually the or defaults are usually symbols:
user=> (let [defaults '{a 1}] (time (dotimes [i 100000000] (contains? defaults 'a) (defaults 'a))))
"Elapsed time: 1583.053364 msecs"
nil
user=> (let [defaults '{a 1}] (time (dotimes [i 100000000] (second (find defaults 'a)))))
"Elapsed time: 6325.311779 msecs"
they are always symbols
enforced by the spec
nope, sorry, I was using second
which causes the slowness:
user=> (let [defaults '{a 1}] (time (dotimes [i 100000000] (val (find defaults 'a)))))
"Elapsed time: 697.04199 msecs"
nil
user=> (let [defaults '{a 1}] (time (dotimes [i 100000000] (contains? defaults 'a) (defaults 'a))))
"Elapsed time: 1593.39499 msecs"
nil
I mean those numbers make sense to me based on what they're doing
the first is one lookup, the second is two
could you try to make a perf test that actually uses destructure
?
> This might be an unimportant performance thing Alex responded: feel free to file a jira. He also could have responded with: not important, bye.
but I'll make a perf test with destructure itself and I'll let it sit there until it's closed in 2028 ;)
again, I asked the core team (Alex) if this was unimportant and the reaction was: feel free to file a JIRA. That's what I did, ok?
there is a non-issue, imho -- lots of macrotime things use the not most performant code
I think it's worth doing - we have chased micro gains in this area in the past given how common destructuring is
you are misreading the ticket @alexmiller
it's not the code emitted by destructuring that is being optimized (which would be worthwhile)
I'm ok with bringing it to rich, he can decide
I'm accepting any outcome, I just found this while fixing a bug in sci. I appreciate the hard work the core team is doing. In the grand scheme of things this may not matter very much and that's ok. I don't find a noticable difference with:
(time (dotimes [i 10000000] (destructure '[{:keys [a] :or {a 1}} {:b 1}])))
(time (dotimes [i 10000000] (destructure2 '[{:keys [a] :or {a 1}} {:b 1}])))
where destructure2
is the patched one.I do see potential speedups in the generated code, e.g. replacing get
with a keyword lookup when :keys
is used, etc, but I haven't considered this longer than core probably has. So I'll leave it at this for now
I didn't mean this sarcastically btw @U050ECB92 . There's so many trade-offs to make and probably this has been considered ages ago.
I see an issue about that here: https://github.com/oracle/graal/issues/2762 Seems like they are working on it. Also the MethodHandle problem in Reflector.java JDK11 would be solved with that.
> Note that the performance of such method handles will be slower compared to the Java HotSpot VM because no dynamic compilation of method handle chains is possible.
interesting, didn't realize https://github.com/oracle/graal/issues/2761 was in progress
Yeah, that would be cool. Currently I work around the problem in Reflector.java like this: https://github.com/borkdude/clj-reflector-graal-java11-fix
I am wanting to replace an old Java service (slow and somewhat buggy) with Clojure. The interface to this system inputs/writes out several XML files marshallled and unmarshalled by JAXB-annotated code. I have the .xsd files defining the 250 or so classes that can be in-/output by this service (and of course, the generated Java classes). Does Clojure have any tools to make this replacement simpler or am I stuck updating the old Java code? So far, I've run across libraries like clj-xsd, which parses .xsd files, but gives no help as to reading/writing the XML data files that might be marshalled/unmarshalled by JAXB. And, although there are one-or-two libraries that mention JAXB, they seem to be moribund/aborted. Has anyone even attempted something like this in the past, or is this a data format that Clojure doesn't have a very good answer for?
I think most clojure solutions deserialize XML to nested maps, obviating the need for classes generated from xsd
nested maps do require more memory than plain java objects
alternatively you can keep JAXB and annotated classes and you can deserialize to those objects, but then use Clojure to process them
That's what I've sort of figured. The sheer number of classes potentially contained by the XML is giving me pause, though. I was thinking if there was some sort of way to generate Clojure code from the .xsd files for marshalling/unmarshalling the XML to records - which can be used like maps, my internal processing would potentially be a bit simpler and I could avoid manually generating the XML output.
Hum.... Not sure a Record uses any less memory then a map. I'd ignore the "fear of maps using more memory" and just parse the XML into maps
Thanks all for your suggestions. They've been helpful. I'll spend a bit more hammock time on this.
clojure.data/diff-associative
is implemented as:
(defn- diff-associative
"Diff associative things a and b, comparing only keys in ks (if supplied)."
([a b]
(diff-associative a b (set/union (keys a) (keys b))))
([a b ks]
...))
But (set/union (keys a) (keys b))
when a
and b
are both regular maps can result in duplicate values because keys
does not return a set-like object:
(clojure.set/union (keys {1 1}) (keys {1 1}))
=> (1 1)
So it seems like diff
might do some useless work because it violates clojure.set/union
contract.
yeah, calling set/union on non-set inputs is a bug
Yes, this is the one place I know of in Clojure's core code that it would violate an imagined spec on clojure.set/union that it only takes sets as inputs.
TIL:
user=> (defn foo:bar [])
#'user/foo:bar
Is this "supported" behavior? I found it here:
https://github.com/littleredcomputer/sicmutils/blob/6dc57d74e6f2ee22688b061012b14fa314636086/src/sicmutils/series.cljc#L58per the reader docs, it seems like it's supported: > Symbols beginning or ending with ':' are reserved by Clojure. A symbol can contain one or more non-repeating ':'s. > https://clojure.org/reference/reader#_symbols