clojure-europe

For people in Europe... or elsewhere... UGT https://indieweb.org/Universal_Greeting_Time
slipset 2020-10-09T04:57:13.301500Z

It’s almost like a lazy transducer?

πŸ˜„ 1
slipset 2020-10-09T04:57:21.301800Z

Good morning btw!

2020-10-09T05:58:33.302100Z

Morning

plexus 2020-10-09T06:54:35.302500Z

Happy Friday!

jasonbell 2020-10-09T07:51:00.303Z

Morning

jasonbell 2020-10-09T07:52:10.303500Z

@dharrigan America: What Time Is Love is still a thing of beauty.

ordnungswidrig 2020-10-09T08:05:51.303800Z

Good morning!

ordnungswidrig 2020-10-09T08:09:43.307200Z

I just saw the discussion about rich comment block. I like them and use them and have colleagues who hate them and remove them left and right. They main argument is that they are often outdated when the codebase changes and should be unit tests actually. This missed the point that they are a vehicle to quickly setup an environment to continue working on the codebase.

1
raymcdermott 2020-10-09T08:10:33.307500Z

morning

thomas 2020-10-09T08:18:27.307800Z

morning. The KLF rules.

thomas 2020-10-09T08:18:41.308100Z

despite burning a million quid.

raymcdermott 2020-10-09T08:29:47.308400Z

despite because

βœ”οΈ 2
borkdude 2020-10-09T08:44:48.308600Z

morning

2020-10-09T08:53:59.309300Z

@ordnungswidrig rich comment blocks afford exploring a code base in a different way from unit tests

borkdude 2020-10-09T08:55:18.309900Z

@ordnungswidrig outdated rich comment blocks: this is also why clj-kondo defaults to linting them. I can see immediately if they are outdated in my editor.

2
2020-10-09T09:07:31.310100Z

πŸ‘

ordnungswidrig 2020-10-09T09:07:38.310400Z

@borkdude Great decision

ordnungswidrig 2020-10-09T09:08:40.311700Z

The problem with them being outdated happens if other developers don’t use them and ignore them when changing the code. As so often it’s a matter of communication and sticking with decisions.

slipset 2020-10-09T09:28:15.314100Z

Oh, a Clojure win. I've been spending my time in some, let's say, poorly written validation code. When I started digging into this, my Java-reptile brain thought: "oh, cool, maybe I can create a lib out of the validation-running logic and open-source it?" After a while, I ended up slightly modifying a core macro in two different ways, and I had what I wanted:

(defmacro first-invalid
  "Returns the result of the first validator which returns non-nil"
  [validator & validators]
  (let [valid? (gensym)
        validations (map (fn [next-validation]
                           `(if-not (nil? ~valid?) ~valid? ~next-validation))
                   validators)]
    `(let [~valid? ~validator]
       ~(if (empty? validations)
          valid?
          (last validations)))))


(defmacro all-invalid
  "Returns the result of all the validators which returns non-nil"
  [& validators]
  (let [validations (vec
                     (keep (fn [next-validation]
                             `~next-validation)
                           validators))]
    `(remove nil? ~validations)))

slipset 2020-10-09T09:29:23.315500Z

And I'm sure they could be written better, but that's not the point, the points are: 1. I've finally produced some interesting macros 2. This would have been a metric shit ton of code in Java.

πŸ‘ 1
borkdude 2020-10-09T09:30:33.316Z

@slipset can you give an example of calls to these macros? only the code is a bit unimaginative to look at

slipset 2020-10-09T09:32:24.317900Z

(all-invalid (validate-user-name username) (validate-first-name firstname) (validate-last-name)) ;; will run all validators
(first-invalid (not-empty? possible-number) (number? possible-number))

borkdude 2020-10-09T09:42:45.318800Z

@slipset isn't first-invalid just or maybe?

slipset 2020-10-09T10:06:17.319Z

You might very well be right.

slipset 2020-10-09T10:06:21.319200Z

Damn!

borkdude 2020-10-09T10:15:22.320Z

For the second one I would probably write a reduce, merge, merge-with or just [], no need for a macro if you want to eval all anyway

slipset 2020-10-09T10:21:47.320600Z

Hmm, I have a bug in my implementation πŸ˜•

slipset 2020-10-09T10:22:27.321200Z

> (all-invalid (error 1) (or (ok) (error 4)) (all-invalid (error 2) (error 3)))
;; => ("ERROR-1" "ERROR-4" (["ERROR-2" "ERROR-3"]))

slipset 2020-10-09T10:22:59.321800Z

I need them to un-nest, and I'm scared of using flatten

borkdude 2020-10-09T10:23:17.322200Z

I wonder if malli has something like "all errors" and "first error"

slipset 2020-10-09T10:23:44.322700Z

I would want this to be ("ERROR-1" "ERROR-4" "ERROR-2" "ERROR-3")

borkdude 2020-10-09T10:26:07.323100Z

a small sprinkle of seq? maybe?

borkdude 2020-10-09T10:28:19.324900Z

(defn collect-errors ([err1 err2] (if (seq? err2 ) (cons err1 err2)) ([err1 err2 & errors] ....)

ikitommi 2020-10-09T11:38:51.327400Z

in malli, the validation errors is a sequence, you can ask just the first. but, populating the sequence is currently eager, for no good reason :thinking_face: validation is optimized to fail-fast on first error.

ikitommi 2020-10-09T11:41:34.329400Z

could be lazy-seq, so the find-first would work as expected. I guess that would be useful in case you have 1000 large items in a sequence to validate and just need to find the first failing reason.

1
2020-10-09T12:28:36.329800Z

what are people using to read/write bzip2 files?

borkdude 2020-10-09T12:37:13.330100Z

@otfrom raynes/fs has a compression namespace for this

borkdude 2020-10-09T12:37:23.330400Z

it uses some apache compression lib under the hood

borkdude 2020-10-09T12:37:39.331Z

the lib is now maintained under clj-commons

2020-10-09T12:37:42.331200Z

cool, that has been adopted by clj commons as well

2020-10-09T12:37:45.331500Z

snap

2020-10-09T12:38:03.331800Z

(I still feel sad about raynes)

borkdude 2020-10-09T12:38:16.332Z

me too!

borkdude 2020-10-09T12:38:46.332500Z

nice fact, the fs.clj namespace can now run from source with babashka

2020-10-09T12:39:23.332800Z

cool

2020-10-09T12:39:34.333100Z

@slipset I like your last comment on that repo

2020-10-09T13:13:20.334600Z

so fs looks good if I want to copy the bzipped file over. I want to read in the lines. I've done that with an eduction before (I think). Are there any good examples of reading in from a file into a transducer that produces records/lines?

2020-10-09T13:13:28.334800Z

(I should dig out my old example)

2020-10-09T13:13:36.335Z

I think cgrand/xforms has something

2020-10-09T13:15:52.335500Z

you are my hero today @borkdude πŸ˜„

2020-10-09T13:16:13.335800Z

ah, building on the grammarly work (that was where I started)

2020-10-09T13:17:29.336300Z

@borkdude glad you saved that as the original has disappeared from their blog

2020-10-09T13:18:22.336900Z

ah, just the link coming from your blog that 404s https://www.grammarly.com/blog/engineering/building-etl-pipelines-with-clojure/

borkdude 2020-10-09T13:18:31.337300Z

I think they changed their links

2020-10-09T13:18:35.337400Z

(cool URLs don't change, didn't anyone tell grammarly that?)

πŸ˜‚ 2
borkdude 2020-10-09T13:24:57.337600Z

Fixed the link on my blog

2020-10-09T13:25:02.337800Z

πŸ†’

2020-10-09T13:25:10.338100Z

this is what I did last time: https://clojurians-log.clojureverse.org/clojure-uk/2017-11-30/1512059055.000520

thomas 2020-10-09T18:02:10.339400Z

I have a Java class like this: java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask but how do I type hint this in order to avoid reflection?

thomas 2020-10-09T18:04:31.339600Z

ok I think I got it....

thomas 2020-10-09T18:07:07.340600Z

type hint the with the whole class path... I tried that... but I got an error else where... type hint that as well. and now it all seems to work.