Fork me on GitHub
Sean Poulter01:09:13

Thanks. It seems we have a gap for CLJS.


hello all, in thread macro execution, is there any way to stop it if any of step fails?


do you mean -> or ->>? then no. there is a some-> which can be used in a similar manner if your functions catch exceptions (or whatever your notion of failure) and return nil. it might be worth your time to build a little system similar to either type or something similar


perhaps some of the clojure's monad libs can be of use here?


ok, I´ll take a look, thank you


What is the opposite of async/alt!? That is, how to retrieve a value from the slowest channel of several?


doesn't seem possible


unless you provide a timeout and at that point you inspect for the last before the timeout?


that could be a neat exercise. sounds quite difficult to do and handle edge cases and not arbitrarily wait


I see. Then what's the easiest way to implement debouncing? If I have a function work that might return too quickly to put in a loop:

How do I modify the loop so that each iteration will take at least 1 second? (So that work will not be called more frequently than once per second)


and its possible it might take up to a second? Usually these situations you can wait on a timeout channel for a second and recur with the understanding that work usually takes up an incredibly small amount of time


No, in this case work can take anywhere from an instant to hours

Alex Miller (Clojure team)03:09:22

I think debouncing is usually done with one of the buffers that drops

Alex Miller (Clojure team)03:09:35

like a chan with a sliding-buffer


this doesn't sound like a good usage for core.async. If you're arbitrarily blocking you should probably submit this to an executor service. and there are scheduled ones that might handle this for you

Alex Miller (Clojure team)03:09:29

I assume by debouncing you're in cljs?

Alex Miller (Clojure team)03:09:26

debouncing is also built into Google Closure library


i'm assuming not if (work) could take hours but not sure


No I'm in CLJ


I came up with this that could work:

  (let [ch (async/timeout 1000)]
    (<! ch))


another thing, if (work) can take hours or return instantly, it seems like perhaps you just wait a second regardless and waiting a second is appropriate if work is instantaneous and completely negligible if work took hours


@dpsutton Thanks. What do you mean by "executor service"?


Looks promising. So I guess these schedules do not have clojure wrappers and are used with Java interops?


correct. but the designers of Clojure have made interop pretty nice and clojure functions implement all of the goodness so that you can just basically (.scheduleWithFixedDelay executor-service work 0 1 TimeUnit/Second)


and you now only have to read the javadocs directly and not some wrapper's docs and then the javadocs backing them to figure out what's going on


Awesome! Thanks!


Any hints on what might be causing > Caused by: java.lang.IllegalArgumentException: No implementation of method: :urls of protocol: #' found for class: jdk.internal.loader.ClassLoaders$AppClassLoader are GREATLY appreciated. Trying to avoid posting long stacktrace in this channel, all the context info is in


Looks like I was using the wrong jdk version


(clojure.pprint/pprint 1) => ClassNotFoundException Is this a separate dependency?


works in REPL not in "code"

Mark Gerard16:09:09

I had this issue earlier and ended up getting it to work by using this`(:use [clojure.pprint :as pp])`

Mark Gerard16:09:17

Note that :use is frowned upon


In an ns form (:require [clojure.pprint :as pp]) (avoid :use -- it refers in every symbol from the namespace, like :refer :all, which is also frowned upon). In the REPL (require '[clojure.pprint :as pp])

Alex Miller (Clojure team)16:09:26

there are a handful of things that are "auto-referred" in the repl, like pprint

Alex Miller (Clojure team)16:09:40

in code, you'll need to require them however


thanks, but not clear to me why fully qualified does not work (clojure.pprint/...)


fully qualified does not cause code to load


fully qualified only lets you reference code that is already loaded


i see, just used to java handling, was perplexed.

Malik Kennedy16:09:39

I expect this to append new entry, but it just resets it to a single :data/:indexes entry

(defn insert  [table record id-key]
  (let [db (read-db)
        new-db {:data {id-key record}
                :indexes [(count (get db :data)) table ]}]

(write-db {})

(write-db (insert :hello {:name :hello :stock 100} 2))

Malik Kennedy16:09:12

(write-db (insert :hello {:name :hello :stock 100} 3))
;; => {:data {:hello {:name :hello, :stock 100}}, :indexes [1 :hello]}

(write-db (insert :hello {:name :hello :stock 100} :hello))
;; => {:data {:hello {:name :hello, :stock 100}}, :indexes [1 :hello]}


@mksybr What do write-db and read-db do? Also, you can use triple-backticks to format blocks of code to make them easier to read:

Like this block
Is easier to read

👀 3
Malik Kennedy18:09:38

(def memory-db (atom {}))
(defn read-db [] @memory-db)
(defn write-db [new-db]
  (reset! memory-db new-db))


@mksybr Since write-db is just resetting the atom to the value it is given, and insert is just returning a single hash map with :data and :indexes, I'm not sure what you expected to happen?


new-db in insert doesn't include any of the previous data so your DB isn't going to grow.


Perhaps you want write-db to (swap! memory-db merge new-db) instead?


Or perhaps insert should return a larger data structure?


(you'll also have a race condition if you start using threads, since your insert function could be called multiple times before write-db so multiple :indexes will have the same value of (count (get db :data))