Fork me on GitHub
#nyc
<
2019-09-11
>
Jeff Shelley14:09:04

does anybody else feel great regret when they need to resort to as-> ?

Jeff Shelley14:09:39

it's bitten me when i want to mix map/reduce/filter with other functions that don't follow that same format

Jeff Shelley14:09:13

maybe I'm missing something, even. i'll paste it next time i run into it

jjttjj14:09:42

I think ideally it's used when you have a single operation in a thread-first chain of operations that has a different/weird signature

(-> {}
    (assoc :x 3)
    repeat
    (as-> x (take 5 x))
    (conj :hello))
This is a pretty horrible example, and ->> would work better here anyway. The clojure core functions tend to be designed to avoid these situtions. But I do hit this in the wild sometimes.

jjttjj14:09:12

This is an actual real world example I used it in lately where I needed to pass the same request data around internally ina lot of places. A let might be better here too but I think this is a place where as-> is ok

(as-> req-vec x
    (ibg/add-id conn x)
    (ibg/add-default-args x)
    (ibg/req-tap conn x (a/chan 1 (comp (ibg/sync-xf x) (ibg/payload-xf x))))
    (a/into [] x)
    (a/<!! x))

Jeff Shelley15:09:05

ah yeah last last second last last. it'd be nicer if there were a way to override this in the nested form itself somehow

Jeff Shelley15:09:40

that's probably a world of pain to do, though

Jeff Shelley15:09:11

i often find myself wanting to make a #() that gets threaded into a ->. i wonder if that's legit

avi15:09:49

I recently replaced an awkward usage of as-> with cond->> Before:

(as-> main it
            (parse-string it)
            (if format (with-msg "formatting" (reformat it)) it)
            (if snap (with-msg "snapping" (snap-to-grid it to-closest min-margin)) it)
            (stringify it)
            (assemble front it)
            (spit file-path it)))))
After:
(-> (parse-string main)
              (cond->>
               format (with-msg "formatting" reformat)
               snap   (with-msg "snapping" #(snap-to-grid % to-closest min-margin)))
              (->> (stringify)
                   (assemble front)
                   (spit file-path))))))
cond->> and cond-> were new to me…

πŸ‘ 4
Jeff Shelley15:09:56

oh i see. needing "it" in both branches of the if

Jeff Shelley15:09:59

yeah that's a bummer

Jeff Shelley15:09:26

i don't think i've used cond->>, myself

jjttjj15:09:23

You can use #() if you just wrap it in parens

(-> 123
    (#(inc %))
    ((fn [x] (str x))))
not pretty but i use this in the repl sometimes

jjttjj15:09:44

Oh I see you meant starting with the function

Jeff Shelley15:09:15

yeah it feels like some hack just to keep the consistency of the ->

Jeff Shelley15:09:30

alas, it's not stopped me from using it! πŸ™‚

jjttjj15:09:09

There was some sort of related discussion on clojureverse recently on some alternative threading macros https://clojureverse.org/t/looking-for-opinion-about-some-macro-ive-been-working-on/4782/19

πŸ‘ 4
Jeff Shelley15:09:24

so diamond wand looks like what i've been missing. where if you don't include a <> in the nested forms it defaults to the behavior of the non-diamond version

πŸ‘ 4
jaide16:09:37

(as-> coll $
      (map transform-data $)
      (filter filter-data $)
      (doseq [item $]
       (println item)))
That's where I think the as-> macro shines. When you're using it with something like doseq where none of the other thread macros would work.

πŸ‘ 4
Jeff Shelley17:09:31

the diamond wand doesn't seem to work here:

(-<>> data
  (map identity)  
  (filter (constantly 1))
  (doseq [item <>]
    (println item)))

Jeff Shelley17:09:32

as-> must do nested replacements where -<>> doesn't, i guess