Fork me on GitHub
#clojure
<
2023-05-01
>
slipset14:05:05

Related to the above: Let’s say I have a fn read-char which I know returns a java char. Since this is a protocol fn, the Clojure compiler boxes this and read-char is typed to return an Object. What would be the fastest way to compare the output of read-char to a known char, eg \" ? I’ve been playing with: 1. (= \" (char (read-char s))) 2. (= 32 (int (read-char s))) 3. (= \" (read-char s)) Looking at the output from the compiler, it seems to me that 2 should be faster, since we then get emitted = whereas the two others use various versions of Util.equiv to do the comparison. I’m sure it’s not sufficient to just look at the decompiled bytecode, since there will probs be some jit stuff involved as well

jpmonettas19:05:11

have you tried criterium quick-benchmark on those?

MegaMatt16:05:21

I’ve been playing a little with datafy+nav. It feels a little like an ERM. Is using it in production code to navigate model relationships a usage that people have opinions on? I’d be curious if people would advise for or against.

Alex Miller (Clojure team)16:05:47

It’s intended for any situation where you need to treat as data something that may be an object graph, so definitely is not a “dev” tool only

👌 1
stopa16:05:03

Hey team, noob concurrency question for you. I want to create a cache, with two usage scenarios: 1. Given a cache at time T, find all K that needs be invalidated, and invalidate them 2. Given a K, lookup-or-miss: either find it, or update the cache with the result for K Now the problem, what would be the best kind of concurrency primitive to wrap this cache in? I could go with the handy atom. This would support 1. Really well. I could easily get a "current view" of the cache at time T, to find all the keys I want to invalidate But, I wonder about 2. If I use an atom, all writes to the cache would contend with each other. It's clear to me that different K 's are not related to eachother, so the contention here is a bit unnecessary. I noticed the recommendation for clojure.core.cache is to use atom though. Is the contention on writes not really a big deal? How would you think about it?

lispyclouds17:05:28

what would be the concern for the contention for writes? the compare and set semantics in an atom should have the desired effect i think?

stopa17:05:01

My thinking is the compare-and-set in the atom would re-run "unnecessarily". if lookup-or-miss runs for two different K , they could conflict, but my thought was "do they really need too?"

lispyclouds17:05:19

yeah atoms are uncoordinated so some unnecessary iterations are expected. the way i understand is because the swapping fn is pure its "fine". works out well in real life

👍 1
seancorfield17:05:37

I would say: try clojure.core.cache.wrapped (which wraps the clojure.core.cached API in an atom automatically) and see how performance is for you.

seancorfield17:05:08

We use c.c.c.w extensively at work for a lot of stuff and haven't had performance problems so far...

seancorfield17:05:03

In reality, it will depend on your usage patterns and what sort of cache invalidation strategy you need. It sounds like you're after TTL which is built-in for c.c.c.w and it already handles (most of) the tricky edge cases with invalidation on access for you.

2
seancorfield17:05:38

(making a bullet-proof cache is hard enough that I wouldn't recommend trying to write one yourself when a Contrib lib already exists for this)

lispyclouds17:05:11

like they say, naming a var and cache invalidation...

😆 3
stopa17:05:56

I'll look deeper into c.c.c.w and see about using it. My usecase is a bit esoteric (I invalidate by listening to Postgers' write-ahead log), but there's lots I can leverage for this in c.c.c.w

dpsutton17:05:20

i think this approach is interesting and i’d like to investigate it more: https://github.com/cnuernber/ham-fisted/blob/master/src/ham_fisted/api.clj#L1121

2
Ben Sless17:05:23

Was going to recommend Caffeine ^

❤️ 2
2
stopa19:05:24

Intrigued! Thanks team, will dive deeper

Matthew Downey21:05:13

Also check out https://github.com/ptaoussanis/encore/blob/master/src/taoensso/encore.cljc#L2557, which makes clever use of https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java + delays as values. Fwiw I think that contention on write is typically not worth worrying about, and if it becomes so, sticking write transactions in a single queue and batch applying them from one thread can get you pretty far.

❤️ 2
stopa14:05:25

This gave me a bunch of good context, thanks team

Craig Brozefsky23:05:20

When I invoke a clojure alias, using clj -M. should I be doing clj -M:foo or clj -Mfoo. both seem to do the same thing

seancorfield00:05:35

Aliases begin with : so -M:foo is correct. Don't rely on -Mfoo continuing to work.

💡 2