clojure-europe

For people in Europe... or elsewhere... UGT https://indieweb.org/Universal_Greeting_Time
2020-09-24T06:02:35.000200Z

Morning

2020-09-24T06:45:48.000700Z

buenos dias, dzien dobry!

bastilla 2020-09-24T06:48:04.001Z

Buongiorno altogether!

plexus 2020-09-24T06:51:50.001500Z

Good morning folks! One step closer to Friday... it's one of those weeks.

3
jasonbell 2020-09-24T07:37:17.002Z

Morning

borkdude 2020-09-24T08:36:12.002200Z

dobrý den

jiriknesl 2020-09-28T12:10:20.086700Z

dobrý den 🙂

thomas 2020-09-24T09:44:51.002500Z

Bono estente

2020-09-24T10:14:01.002600Z

the feeling when not sure if it’s russian or ukrainian

borkdude 2020-09-24T10:19:43.002800Z

Czech my friend

2020-09-24T11:34:18.003100Z

oh right there are more slav languages

2020-09-24T11:35:26.003700Z

mmm... today I shall be using cond-> transient and persistent!

💣 1
2020-09-24T11:35:58.004Z

oh, and assoc!

2020-09-24T11:46:18.004300Z

so... a bit of record-scrubbing

(defn scrub-record [{::keys [id birthday start end placement] :as rec}]
  (let [t (transient rec)]
    (cond-> t
      id (assoc! ::wce/id id)
      start (assoc! ::wce/report-date (t/date start))
      end   (assoc! ::wce/ceased (t/date end))
      birthday (assoc! ::wce/birthday (t/date birthday))
      placement (assoc! ::wce/placement placement)
      true (persistent!))))

(def scrub-records-xf
  (map scrub-record))

2020-09-25T10:12:08.036Z

why not use defrecord ? it would might be less surprising... and transient stops being an issue IIRC

2020-09-24T11:47:11.005Z

I feel a bit dirty about the true at the end of the (cond->), but I like that more than wrapping the whole thing in a -> around the cond->

dominicm 2020-09-24T11:47:47.005600Z

I like true too

slipset 2020-09-24T11:47:59.006100Z

Why not just a persistent! around the cond->

slipset 2020-09-24T11:48:17.006600Z

You don’t have to thread everything.

2020-09-24T11:48:25.006800Z

I like doing either threading or inside out

2020-09-24T11:48:59.007Z

tho I've not got a good reason

borkdude 2020-09-24T12:01:24.008500Z

I wonder if the Clojure compiler folds this:

user=> (macroexpand '(cond :else 1))
(if :else 1 (clojure.core/cond))
into just 1. Should look at the bytecode... Apparently not:
user=> (clj-java-decompiler.core/decompile (fn [] (if :else 1)))

// Decompiling class: user$fn__207
import clojure.lang.*;

public final class user$fn__207 extends AFunction
{
    public static final Keyword const__0;
    public static final Object const__1;

    public static Object invokeStatic() {
        final Keyword const__0 = user$fn__207.const__0;
        if (const__0 != null) {
            if (const__0 != Boolean.FALSE) {
                return user$fn__207.const__1;
            }
        }
        return null;
    }

    @Override
    public Object invoke() {
        return invokeStatic();
    }

    static {
        const__0 = RT.keyword(null, "else");
        const__1 = 1L;
    }
}

borkdude 2020-09-24T12:03:53.010Z

So everytime you write (cond ... :else :foo) you actually contribute to global warming, go figure. ;P

ordnungswidrig 2020-09-25T08:43:23.034600Z

Compare?

ordnungswidrig 2020-09-25T08:44:41.034800Z

Two tests: that one with case and one without wherr you skipped that true clause check. Criterium should be able to warmup hotspot sufficiently.

borkdude 2020-09-25T08:51:31.035700Z

That's only measuring. But how can we see that hotspot is really not hitting that path anymore

raymcdermott 2020-09-24T12:04:13.010300Z

would be nice if all the stuff that @mfikes has done in CLJS to optimise and short-circuit these conditions were brought back into Clojure

slipset 2020-09-24T12:29:45.011100Z

@borkdude You should try the same for cljs.

borkdude 2020-09-24T12:30:26.011300Z

cljs.user=> (str (fn [] (if :else 1)))
"function (){\nreturn (1);\n\n}"
🎉

ordnungswidrig 2020-09-24T12:50:29.011800Z

Guten Nachmittag.

ordnungswidrig 2020-09-24T12:51:30.012Z

A quite univeral expression in slavic languages, right? Spelling and details vary though?

ordnungswidrig 2020-09-24T12:53:06.012200Z

I typically use :alwaysinstead of true for a catch-all in conds.

➕ 1
ordnungswidrig 2020-09-24T12:53:38.012500Z

Naaa, pretty sure hotspot would catch this?!

borkdude 2020-09-24T12:53:41.012700Z

Guten vor-Feierabend

borkdude 2020-09-24T12:54:14.012900Z

How to check?

ordnungswidrig 2020-09-24T12:54:31.013300Z

After work is before work.

2020-09-24T13:36:05.014800Z

Bon après-midi !

2020-09-24T14:32:59.014900Z

ooh. I like that

2020-09-24T15:09:34.015200Z

I like that this is getting out of hand

2020-09-24T15:09:38.015400Z

and good afternoon

raymcdermott 2020-09-24T15:16:15.016100Z

I don't read threads so I'll never find out 🙂

2020-09-24T15:17:43.016600Z

@raymcdermott does this feel like a legible and reasonable use of transient? https://clojurians.slack.com/archives/CBJ5CGE0G/p1600947978004300

2020-09-24T15:17:46.017Z

😉

raymcdermott 2020-09-24T15:26:09.017200Z

damn you!

raymcdermott 2020-09-24T15:26:50.017700Z

did you already explain why you need them?

ordnungswidrig 2020-09-24T15:27:17.017800Z

If speed is your concern here. 🤷

borkdude 2020-09-24T15:29:30.018600Z

since you use multiple assoc! why not combine them in a single one? assoc! already has support for that

borkdude 2020-09-24T15:30:08.019100Z

oh I see, it's in cond->, never mind

raymcdermott 2020-09-24T15:34:22.020200Z

^^^ didn't quite pass the totally legible test 🙂

raymcdermott 2020-09-24T15:35:16.021100Z

I know @borkdude is not such an advanced developer but still

❤️ 2
borkdude 2020-09-24T15:39:21.021400Z

(deftype Foo [m]
  clojure.lang.Associative
  (assoc [this k v]
    (if v
      (Foo. (assoc m k v))
      this))
  clojure.lang.ILookup
  (valAt [this k]
    (get m k))
  Object
  (toString [this]
    (str m)))

(let [v (assoc (Foo. {})
               :a false
               :b nil
               :c 3
               :d 4)]
  (prn v)
  (prn (get v :c)))
#object[user.Foo 0x695a69a1 "{:c 3, :d 4}"]
3
:thinking_face:

borkdude 2020-09-24T15:45:21.021800Z

we actually have a function for this in our codebase at work (uses transients):

(defn nn-hash-map
  "Like c.c/hash-map but does not include false or nil values."
  [& keyvals]
  ...
    ret))

orestis 2020-09-24T15:46:35.021900Z

☝️

2020-09-24T16:05:19.023200Z

@borkdude I've written things like that in the past. This feels like a reasonably quick use of the std lib (tho I've only done it this way today so I'm not devoted to the idea)

borkdude 2020-09-24T16:08:54.024100Z

yeah, seems fine to me

pez 2020-09-24T16:12:53.024800Z

It's quite readable, I would say.

2020-09-24T16:12:56.025100Z

is this a reasonable use of a transient?

2020-09-24T16:13:36.025200Z

it gets called for a fair few records, so I'd like it to be quick. It currently takes around 41 seconds to process the data I'm working with

2020-09-24T16:13:45.025400Z

so there might be some other wins hidden around

borkdude 2020-09-24T16:44:34.026100Z

use of transients is probably reasonable if you have measurable performance benefits

2020-09-24T16:48:47.026700Z

Cool. Looks like i should measure then 😉

😝 1
raymcdermott 2020-09-24T19:07:21.027300Z

I like that you challenged the meaning of legibility there @borkdude