Fork me on GitHub
#beginners
<
2020-05-02
>
sfyire00:05:48

seems to work no problem did a refactor to use clj-new and the app survived πŸ˜„

nicholas.jaunsen16:05:29

Do Clojure future or promise provide an API for listening for completion/failure asynchronously?

seancorfield17:05:49

@nicholas.jaunsen No, but if you're using Clojure on the JVM you can use Java's CompletableFuture for that I suspect.

seancorfield17:05:15

(and in ClojureScript, I think you can interact with JS promises? I don't do cljs tho')

seancorfield17:05:19

At work we have some macros that make it easier to use -- see the examples at the end of the README https://github.com/worldsingles/commons

hammerha20:05:53

Hello, I’m trying to use ClojureScript with quil, rein, and figwheel. I’m running repl and try to run some function but it throws an error that I don’t understand. Can someone explain why this is happening?

hammerha21:05:34

Got an answer https://github.com/quil/quil/issues/176. It turned out that quil APIs are not very repl friendly.

timur05820:05:39

Hi guys, really need your insight, my brain got stuck on this basic thing.

(->> collection (map :optional-param) (filter some?) (apply min))
I'd love to find the minimum of :optional-params in the collection, or nil if no such non-nil values exist. The code above does not work when collection does not have such elements. Is there an idiomatic and beautiful way of doing it without breaking the beautiful thread and without defining an "extended" min with 0 arity that returns nil?

timur05821:05:10

Ok, found that I can simplify the form above to a very cool

(->> collection (keep :optional-param) (apply min))
Didn't yet find elegant short-circuiting of empty seqs.

jason35821:05:38

... seq (#(or % '(nil))) (apply min) will do the trick, but you ain't gonna win any beauty contests with it

jason35821:05:26

or, you know, you could just (some->> collection (keep :optional-param) seq (apply min))

seancorfield22:05:50

Yup, some-> and some->> are great for short-circuiting threading pipelines.

seancorfield22:05:20

Nice trick with seq there too!

jason35822:05:00

I don't love that it does unneeded nil checks, though

jason35822:05:54

(seq (keep :whatever collection)) would avoid that, but then it just looks less "pretty" πŸ™‚

seancorfield22:05:49

(some->> (seq (keep :whatever collection)) (apply min))

seancorfield22:05:14

I think that's reasonable.

jason35822:05:52

On the other other hand, a sufficiently smart compier β„’ would know that keep can't return nil , so that check could be optimized away πŸ™‚

noisesmith22:05:21

clojure's compiler has no intention of ever being smart

noisesmith22:05:37

or, to be less glib, the designers of the clojure compiler explcitly aren't trying to be clever, and they will rearrange things as they are found to be bottlenecks but prefer better internal design to cleverness in the compiler implementation. if extra nil checks inside a lazy-seq pipeline is your bottleneck there's a lot you can do to improve speed before the compiler needs to get complicated

jason35823:05:09

it seems like a relatively low hanging fruit in compile time optimizations though, just some type inference and dead branch elimination

noisesmith23:05:39

anybody in any thread can redefine keep at any time

noisesmith23:05:53

so as a static check, it doesn't fit clojure's compilation model, and as a runtime check the extra logic would just make it harder for hotspot to do its job

noisesmith23:05:33

(and would be more expensive than the original nil check, which is very low overhead)

jason35823:05:22

inlining a happy paths + a guard for redefinition / slow path seems like a pretty usual JIT approach, I'm not convinced it can't be beneficial here

noisesmith23:05:55

we have a JIT, it's called hotspot, adding your own JIT logic makes hotspot less efficient

noisesmith23:05:26

I mean, you're welcome to try this sort of thing, of course, the project is open source, but RH has been explicitly averse to these sorts of changes

jason35823:05:08

I'm absolutely not saying you should add your own, but isn't hotspot smart enough to do things like that sometimes?

jason35823:05:49

I mean, it knows the return type and it knows it's a nil check

noisesmith23:05:14

it can, and that sort of thing can be done for you if you keep your bytecode simple enough

noisesmith23:05:28

it knows the return type of the invoke method of a specific object, we call that object keep, to the bytecode / vm it's a specific class in clojure.core with an invoke method. And yes, hotspot can and will optimize that method if it has bytecode it knows how to improve.

noisesmith23:05:58

@ I think I misunderstood your point, apologies

jason35823:05:32

no problems, I absolutely did miss that thing about redefs

jason35823:05:31

I assumed redefs don't affect "already compiled" stuff, and had to do a quick experiment in repl to see that it's indeed wrong

noisesmith00:05:00

there's a trick where you can use a binding context (function arg, let block), the right hand side will see redefs (it's attached to the var), but the lhs, the new binding, is captured and isn't resolved again

noisesmith00:05:36

it's more often you see the "counter-trick" to that trick, of using the #'var quoting of the var to ensure the new binding sees your redefs :D

jason35800:05:12

yeah, the #'var thing is why I assumed that

jason35800:05:43

so, thanks for the explanation πŸ™‚