Fork me on GitHub
#clojure-europe
<
2020-10-09
>
slipset04:10:13

It’s almost like a lazy transducer?

πŸ˜„ 1
slipset04:10:21

Good morning btw!

plexus06:10:35

Happy Friday!

jasonbell07:10:10

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

ordnungswidrig08:10:43

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
thomas08:10:27

morning. The KLF rules.

thomas08:10:41

despite burning a million quid.

raymcdermott08:10:47

despite because

βœ”οΈ 2
otfrom08:10:59

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

borkdude08:10:18

@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
ordnungswidrig09:10:40

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.

slipset09:10:15

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)))

slipset09:10:23

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
borkdude09:10:33

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

slipset09:10:24

(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))

borkdude09:10:45

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

slipset10:10:17

You might very well be right.

borkdude10:10:22

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

slipset10:10:47

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

slipset10:10:27

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

slipset10:10:59

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

borkdude10:10:17

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

slipset10:10:44

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

borkdude10:10:07

a small sprinkle of seq? maybe?

borkdude10:10:19

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

ikitommi11:10:51

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.

ikitommi11:10:34

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
otfrom12:10:36

what are people using to read/write bzip2 files?

borkdude12:10:13

@otfrom raynes/fs has a compression namespace for this

borkdude12:10:23

it uses some apache compression lib under the hood

borkdude12:10:39

the lib is now maintained under clj-commons

otfrom12:10:42

cool, that has been adopted by clj commons as well

otfrom12:10:03

(I still feel sad about raynes)

borkdude12:10:46

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

otfrom12:10:34

@slipset I like your last comment on that repo

otfrom13:10:20

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?

otfrom13:10:28

(I should dig out my old example)

otfrom13:10:36

I think cgrand/xforms has something

otfrom13:10:52

you are my hero today @borkdude πŸ˜„

otfrom13:10:13

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

otfrom13:10:29

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

borkdude13:10:31

I think they changed their links

otfrom13:10:35

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

πŸ˜‚ 2
borkdude13:10:57

Fixed the link on my blog

thomas18:10:10

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

thomas18:10:31

ok I think I got it....

thomas18:10:07

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.