Fork me on GitHub
#clojure
<
2022-06-20
>
tabidots02:06:38

IDE question: I recently heard that http://github.blog/2022-06-08-sunsetting-atom/, which makes me super sad. I guess VS Code + Calva is the closest alternative? How similar are the two? Besides some really great editor themes, my Atom setup is pretty low-key: Paredit, Parinfer + rainbow parens, Chlorine, and occasionally clj-kondo.

mauricio.szabo03:06:23

There's actually a huge force behind Atom-Community right now trying to keep everything alive. It'll probably be rebranded, but we'll probably be able to keep the editor alive, hopefully

❤️ 1
mauricio.szabo03:06:39

If you want to follow things, I have a fork where I'm also trying to renovate some elements (like Electron versions): https://github.com/AtomRebirth/atom

mauricio.szabo03:06:56

Probably really soon I'll start to publish somewhat "nightly" packages too

seancorfield05:06:23

@UGHNF0CS3 if you're not already in the #chlorine-clover and #atom-editor channels, you should join those.

1
Jeongsoo Lee05:06:11

If I have a map and want to extract values associated with keys which in turn comes from a vector of keys (while retaining the order), I would do:

(let [temp-map {:x 1 :y 2 :z 3}]
  (reduce (fn [acc key]
            (conj acc (temp-map key))) [] [:y :x :z]))
;; => [2 1 3]
Is there a core function that achieves this behavior?

p-himik05:06:45

Maps are callable:

(mapv temp-map [:y :x :z])

thanks3 1
1
Jeongsoo Lee05:06:48

Oh, the whole reduce .. logic is actually mapping a function; why did I overlook it..??

Jeongsoo Lee05:06:00

Actually it might be fun to write a linting rule that swaps reduce calls to map or filter

Alex Miller (Clojure team)07:06:27

user=> ((apply juxt [:y :x :z]) {:x 1 :y 2 :z 3})
[2 1 3]

👍 1
1
wizard 1
Jeongsoo Lee07:06:06

wow, in this case the keyword is playing the callable role.

Alex Miller (Clojure team)07:06:32

yeah, think of keywords as "data extractor functions", and juxt as a way to make a function that applies multiple data extractors

1
Yarden Laifenfeld14:06:05

Hi! I’m trying to debug a go-loop (using intellij and cursive) but when I place a breakpoint inside the loop I get an error that says there is no executable code found on that line. Is there something I can do to make this line debuggable?

(defn func []
  (go-loop []
    (let [x (<! c)]
      (println "Got a value in this loop:" x))
    (recur)))
(Placing a breakpoint on the println line)

Ben Sless14:06:59

Go loops aren't really debuggable What are you trying to achieve?

Yarden Laifenfeld14:06:10

I’m guessing if I export the inner part of the loop to a function I can debug that, right?

rolt16:06:22

yes (at least it works in emacs, it should work too in intellij)

rolt16:06:12

go-loop rewrite its whole body as a state machine

Ben Sless16:06:53

The go macro completely tears apart your code, I don't know how a debugger would even begin there So changing the approach - what is your goal?

Ben Sless17:06:24

Ideally you wouldn't need a debugger there , so I'm trying to follow from the root need which led to the conclusion of "I want to debug this"

Yarden Laifenfeld17:06:11

I was hoping to add the capability of debugging go-loops, and wanted to understand if I’m missing something and if there are any debuggers out there that already implement it.

Ben Sless17:06:46

Maybe flowstorm can handle it

Yarden Laifenfeld17:06:43

I’ll take a look, thanks so much!!

Ben Sless17:06:05

Is there a specific purpose or use case in mind of are you doing this for fun?

cjohansen18:06:34

Generally I try to keep go blocks as tiny as possible, calling out to regular functions, exactly because the macro makes the code incomprehensible

☝️ 2
noisesmith16:07:27

something that helps a lot here is log oriented rather than step-oriented debugging. you can use add-tap and tap> to capture immutable data in context and append to an atom, then browse the values in order, and experiment with them as needed.

(cmd)user=> (def captured (atom []))
#'user/captured
(cmd)user=> (defn capture-data [[k v]] (swap! captured conj {k [(System/currentTimeMillis) v]}))
#'user/capture-data
(ins)user=> (for [i (range 10)] (do (tap> [:outer {:i i}]) (for [j (range 10)] (do (tap> [:inner {:i i :j j}]) [i j]))))
(([0 0] [0 1] [0 2] [0 3] [0 4] [0 5] [0 6] [0 7] [0 8] [0 9]) ([1 0] [1 1] [1 2] [1 3] [1 4] [1 5] [1 6] [17] [1 8] [1 9]) ([2 0] [2 1] [2 2] [2 3] [2 4] [2 5] [2 6] [2 7] [2 8] [2 9]) ([3 0] [3 1] [3 2] [3 3] [3 4] [3 5] [3 6] [3 7] [3 8] [3 9]) ([4 0] [4 1] [4 2] [4 3] [4 4] [4 5] [4 6] [4 7] [4 8] [4 9]) ([5 0] [5 1] [5 2] [5 3] [5 4] [5 5] [5 6] [5 7] [5 8] [5 9]) ([6 0] [6 1] [6 2] [6 3] [6 4] [6 5] [6 6] [6 7] [6 8] [6 9]) ([7 0] [7 1] [7 2] [7 3] [7 4] [7 5] [7 6] [7 7] [7 8] [7 9]) ([8 0] [8 1] [8 2] [8 3] [8 4] [8 5] [8 6] [8 7] [8 8] [8 9]) ([9 0] [9 1] [9 2] [9 3] [9 4] [9 5] [9 6] [9 7] [9 8] [9 9]))
(ins)user=> (count @captured)
110
(cmd)user=> (nth @captured 55)
{:inner [1656691454460 {:i 4, :j 5}]}
(ins)(user=> (->> @captured (drop 54) (take 10))
({:inner [1656691454460 {:i 4, :j 4}]} {:inner [1656691454460 {:i 4, :j 5}]} {:inner [1656691454460 {:i 4, :j 6}]} {:inner [1656691454460 {:i 4, :j 7}]} {:inner [1656691454460 {:i 4, :j 8}]} {:inner [1656691454460 {:i 4, :j 9}]} {:inner [1656691454460 {:i 5, :j 0}]} {:inner [1656691454460 {:i 5, :j 1}]} {:inner [1656691454460 {:i 5, :j 2}]} {:inner [1656691454460 {:i 5, :j 3}]})
user=>

noisesmith16:07:53

and I accidentally made a nice demo of counterintuitive chunking behavior

(ins)user=> (->> @captured (map #(cond (:outer %) :outer (:inner %) :inner :else :huh?)))
(:outer :outer :outer :outer :outer :outer :outer :outer :outer :outer :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner :inner)
(cmd)user=>

micah15:06:30

I’m getting intermittent erorrs when using this technique to dynamically load namespaces.

(require ns-sym) (the-ns ns-sym)
Every once in a while a JVM process will spin up and throw No namespace: <ns-sym> found errors. Any idea what would cause this problem and how to resolve it?

eskos16:06:25

For dynamic ns loading I tend to use https://github.com/borkdude/dynaload

eskos16:06:53

There's also https://clojuredocs.org/clojure.core/requiring-resolve if that's your thing - not entirely sure what your goal is, so just dropping some links here 🙂

micah16:06:57

requiring-resolve may be the solution… that’s a fairly new addition to clojure.core… Thanks for the link!

seancorfield18:06:15

requiring-resolve is thread safe, plain require is not. There's a serialized-require in core (behind requiring-resolve) but I think it's private.

micah18:06:52

Thanks @U8SFC8HLP and @U04V70XH6. I’ve updated and testing the use of requiring-resolve and so far it’s working great.