This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-06-18
Channels
- # announcements (35)
- # babashka (31)
- # beginners (77)
- # biff (23)
- # calva (1)
- # clj-kondo (4)
- # cljsrn (3)
- # clojure (71)
- # clojure-dev (9)
- # clojure-europe (51)
- # clojure-france (3)
- # clojure-germany (1)
- # clojure-nl (3)
- # clojure-spec (9)
- # clojure-uk (42)
- # clojurescript (24)
- # clojureverse-ops (3)
- # component (16)
- # cursive (1)
- # data-science (8)
- # emacs (1)
- # fulcro (5)
- # graalvm-mobile (1)
- # graphql (2)
- # honeysql (36)
- # leiningen (3)
- # malli (3)
- # off-topic (16)
- # remote-jobs (1)
- # sql (3)
- # testing (19)
- # tools-deps (11)
- # xtdb (20)
Just watched @tcrayford video https://www.youtube.com/watch?v=0tUrbf6Uzu8 What is the performance of small collections in Clojure now? @alexmiller @ztellman @ptaoussanis do we still need https://clojure.atlassian.net/browse/CLJ-1517 and https://clojure.atlassian.net/browse/CLJ-1610 ?
Perhaps an update of this talk would be in order š Some performance tips on ClojureScript would also be great.
Ok, seems to be still half open/ there is no closing words for that proposal if I understand it correctly.
IIRC, the benchmarks were oriented around monomorphic calls, which HotSpot excels at optimizing, but the increased # of classes seen at critical call sites (e.g. RT/assoc) turned those call sites megamorphic. Those kinds of call sites have the worst performance
some really good analysis of a similar failed optimization effort here https://github.com/google/guava/issues/1268 @adam.kalisz
> Guava ImmutableList (and others) offer awful performance in some cases due to size-optmized specializations
Thanks! I have added a comment below the YouTube talk. I would appreciate a summary, these tickets leave a sour taste when the case wasn't so clear after all. š
I donāt think the idea is dead. Rich would still love to have tuples. They just need to be performant. There are lots of new tools in Java since this work that may offer new choices
@adam.kalisz I think Richās comments in CLJ-1517 are pretty clear on the performance problems (but CLJ-1610 could benefit from a comment at least pointing to why CLJ-1517's original approach wasnāt accepted).
(and itās nice to see the link to the Guava issue ā in Colinās comment on CLJ-1517 ā I had stopped following the issue by that point I think so itās very interesting to read about that failed optimization too!)
It was weirdly contemporaneous iirc
(such a map optimization would still have to defeat the megamorphic issue mentioned above)
In learning clojure, what is the ONE thing that if you practice regularly, you will become a a great clojure programmer?
You might get better responses in #beginners since folks there have opted in to helping/teaching new folksā¦
Always work in your editor, never type into the REPL. Always evaluate every change you make as you make it (you donāt even need to save the file!). Use Rich Comment Forms (i.e., (comment ..)
) for all of your āscratchā ideas and exploration ā and usually keep it in place in the final code so you can see how you got there. Be able to run tests via the REPL from your editor, so youāre not switching contexts. Develop good REPL hygiene so you can keep a REPL running for days (or weeks, or even months) without restarts or ārefreshā tooling.
![thanks2](https://emoji.slack-edge.com/T03RZGPFR/thanks2/50a7eae6ac7040b9.gif)
Thank you, @U04V70XH6! I will ask in #beginners but thank you a lot for the response!
> Always work in your editor, never type into the REPL. As an autodidact I dabbled in Clojure for at least a year before I really understood this, or REPL-driven development generally. Wish I'd heard it stated plainly like this! š
I hadnāt really thought about it being an issue until Stu Halloway said in one of his talks that he was āalways baffled when he saw people typing into the REPLāā¦
https://github.com/matthiasn/talk-transcripts/blob/master/Halloway_Stuart/REPLDrivenDevelopment.md ā āSave everything. Your interactions with the REPL -- I am baffled when people type things into the REPL. We will talk about that a bit more in a second.ā
(the whole talk is excellent)
> Develop good REPL hygiene so you can keep a REPL running for days (or weeks, or even months) without restarts or ārefreshā tooling.
While we're on the subject, do you have any recommended reading about this? I've been using mount
and generally getting better at this but my progress has been pretty piecemeal. Usually have to restart my REPL at least once a day to hack around various things I don't fully grok yet.
> In learning clojure, what is the ONE thing that if you practice regularly, you will become a a great clojure programmer? Jumping to the source to understand what you're invoking. And favoring the use of said source over querying documentation, issue trackers, etc
@UH85MNSKE āWhile weāre on the subject, do you have any recommended reading about this?ā Well, thereās the whole https://clojure.org/guides/repl/introduction series ā especially the last two sections (Enhancingā¦, Guidelinesā¦). Stuās talk is excellent, @U0522TWDA just posted a video of RDD (in the #news-and-articles channel: https://clojurians.slack.com/archives/C8NUSGWG6/p1623857070131800 ) and that thread contains more links ā including Stuās talk and my demo to London Clojurians from December showing RDD. And thereās also a link in that thread to this set of resources: https://clojure.org/guides/repl/annex_community_resources
With regards to unrolling, I did find significant performance improvements when unrolling rest-args or keys sequences when they're known at call site. The difference between (get-in m [k1 k2])
and (-> m (get k1) (get k2))
is significant and surprising. Same with assoc
You might enjoy looking at https://github.com/redplanetlabs/specter which has similar performance to unrolled, but has an interface which is even nicer than the higher-level clojure functions, especially when dealing with highly-nested data.
I'm familiar with spectre but my design goal was to stick as close as possible to Clojure's semantics, with the ability of providing a drop in replacement, so users don't have to learn a new language. My implementation passes the core test suit.
you can see the results here: https://github.com/bsless/clj-fast/blob/master/doc/results.md#get-in It's basic loop unrolling
Did you check if it has that same megamorpgic issue the ticket refers too for real-life use cases? (No idea what megamorpgic refers too so I don't really know of relevant to get-in)
https://en.m.wikipedia.org/wiki/Inline_caching jitted jvm method calls will emit certain instruction sequences depending on if a call is monophonic (only invoked with a single target type), polymorphic (some small, maybe 2, different target types), or megamorphic (many target types, full real dispatch through a method table)
I got error Clojure can't invoke "java.util.concurrent.Future.get()" because "fut" is null
.
Here is the details, the source code caused error:
(defn long-func []
(let [p (promise)]
(.start (Thread. (fn []
(Thread/sleep 5000)
(deliver p "hello!"))))))
;;; this expr will wait for 5 seconds.
(deref (long-func))
And here is the stacktrace:
Show: Project-Only All
Hide: Clojure Java REPL Tooling Duplicates (13 frames hidden)
1. Unhandled java.lang.NullPointerException
Cannot invoke "java.util.concurrent.Future.get()" because "fut" is null
core.clj: 2304 clojure.core/deref-future
core.clj: 2324 clojure.core/deref
core.clj: 2310 clojure.core/deref
REPL: 8 user/eval7232
REPL: 8 user/eval7232
Compiler.java: 7181 clojure.lang.Compiler/eval
Compiler.java: 7136 clojure.lang.Compiler/eval
core.clj: 3202 clojure.core/eval
core.clj: 3198 clojure.core/eval
interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn/fn
AFn.java: 152 clojure.lang.AFn/applyToHelper
AFn.java: 144 clojure.lang.AFn/applyTo
core.clj: 667 clojure.core/apply
core.clj: 1977 clojure.core/with-bindings*
core.clj: 1977 clojure.core/with-bindings*
RestFn.java: 425 clojure.lang.RestFn/invoke
interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn
main.clj: 437 clojure.main/repl/read-eval-print/fn
main.clj: 437 clojure.main/repl/read-eval-print
main.clj: 458 clojure.main/repl/fn
main.clj: 458 clojure.main/repl
main.clj: 368 clojure.main/repl
RestFn.java: 1523 clojure.lang.RestFn/invoke
interruptible_eval.clj: 84 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 56 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 152 nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
AFn.java: 22 clojure.lang.AFn/run
session.clj: 202 nrepl.middleware.session/session-exec/main-loop/fn
session.clj: 201 nrepl.middleware.session/session-exec/main-loop
AFn.java: 22 clojure.lang.AFn/run
Thread.java: 831 java.lang.Thread/run
My computer environment:
- operating system: macOS Big Sur (Version 11.4) (M1 Apple Sillicon)
- Clojure version: ā1.10.3ā
- Java version: OpenJDK 17You have to return the promise
Which you're not doing
(defn long-func []
(let [p (promise)]
(.start (Thread. (fn []
(Thread/sleep 5000)
(deliver p "hello!")))
p
)))
I see. Let me take a try. Thanks @UJ1339K2B
Problem solved. the returned p
need to put out side of (.start ā¦)
sexp. Thanks a lot! I thought this might be a bugā¦. how stupid.
unrelated to your question, the core future
function returns a dereffable thing to get the result of a thread (like you have here) but with proper dynamic binding behavior and using a thread pool for efficiency
I see. Thanks for your suggestion. I will learn.
Hey guys, Clojure programming in Emacs, any tips? Of course I know about Cider, but apart from that? I understand the Clojure people are keen on ParInfer (for Emacs that'd be https://github.com/justinbarclay/parinfer-rust-mode then I imagine) more so than on the default Emacs paredit? (I'm yet to try ParInfer, I used to use Lispy and the Lispy EVIL thing before when working in Common/Emacs Lisp.) I'm an EVIL user (the Vim emulation for Emacs that is). So working in multiple modes is really preferred, being all the time in insert mode is really not my preference. Still ā I'm happy to try anything that has potential.
You can become pretty productive if you just learn 2-3 paredit type commands. Some that I use all the time that I recommend learning the keybinds for: ā¢ Slurp forwards (makes it easy to surround code with an if/when/let, etc) ā¢ Splice Sexp killing backwards (makes it easy to undo the above) ā¢ Kill sexp
I like to use both paredit and parinfer at the same time. For me parinfer is awesome for straight-line coding but awful for significant editing, where paredit really shines. Parinfer also has two modes, and I find it indispensible to be able to toggle easily between them, so I added this lifesaver keybinding:
(evil-global-set-key 'insert (kbd "C-p") 'parinfer-toggle-mode)
(evil-global-set-key 'normal (kbd "C-p") 'parinfer-toggle-mode)
I can see which mode I'm in because the strict mode has rainbow parens visible, and the regular mode does the grey-out parens thing, which I find very intuitive, but took some work to get working. I also ran into problems with the rust variant of parinfer so fell back to the original which is slightly slower on huge files but in practice is never a problem.
I agree with the above comment on learning some basic paredit commands, but would encourage you to gradually learn them all š Even the weirdo C-? is awesome about once every couple of days...in my experience parinfer is more popular for people without lisp experience(?) but ymmv, and agreed that parinfer is great when first writing the code but becomes inconvenient when editing later (but I haven't touched it in years)
I am not a fan of parinfer and stay with paredit. Simple, always works, and I direct it rather than it trying to figure out what indentation i need. it seems basically backwards. things should indent on the nesting i provide, not assume the nesting based on indentation. as for modal editing, I don't know of any reason that you should have to switch to non-modal editing
I think the main thing with clojure people being keen on parinfer is that it's a useful tool for beginners to get into the language if they're unused to lispy syntax. Almost every clojure developer I've spoken to who started with parinfer has "graduated" to other structural editing packages.
FWIW I regularly teach new Clojure programmers and I strongly discourage parinfer. I think it is actively counterproductive, although I appreciate that it is clever and that some people like it. What I seek both for the new Lispers I teach and for myself (a lisper for 35+ years) is something that acts as close as possible to a generic text editor, but with (crucially) good bracket matching and auto-re-indentation. No parinfer, no paredit, nothing that gets in the way of existing typing/cutting/pasting habits.
Right, I wasn't aware of that. So basically on front of structural editing, I might as well stick to Lispy/Lispyville then.
So structural editing + Cider would then be the typical way of working with Clojure in Emacs then I reckon?
That is how I work. Lispy(ville) + Cider. I think if you can get really good lispy muscle-memory, that is about as good as any structural editing support out there.
@suskeyhose I've been using parinfer for years now. Can't work with anything else productively
Iāve gone back and forth between Paredit and Parinfer multiple times over the 11 years Iāve been doing Clojure. I like some aspects of both and I dislike some aspects of both. For the last several years, I was using them together, first in Atom, then in VS Code, but now Iām using Calva (+ Chlorine) so Iām only using Paredit. I think Paredit takes a lot more getting used to and itās a lot more powerful ā but you need to learn/remember a lot more commands to be productive. I found Parinfer mostly did what I expected/needed but missed the more powerful structural stuff that Paredit adds. When I used them together, I disabled some of Pareditās indent/paste stuff in order to let Parinfer do its thing.
Calva Peredit plays pretty well with the Parinfer extension. You'll need to disable Calva's indent-as-you-type, though.
In cursive with paredit, you can be up to normal code-editing productivity, if not higher, just by knowing 1 keybind (Ctrl-W for "Expand selection")
I just live off indentation and re-indentation, and parens-balancing highlighting. I know how to edit, thanks. But I have been Lisping for 25 years... I had a fling with Paredit, not sure what ended the relationship. I might have forgotten its birthday...
Hmm, The Google is failing me. I saw some ADR templates somewhere, cannot find it now. Any recommendations? š
That's it! Thx. š