Concurrency
clove runs on one OS thread. Concurrency comes from coroutines: a future, a go block or an agent action runs as a fiber, and fibers switch whenever one waits, whether on a channel, a deref, Thread/sleep, or a socket. One scheduler runs all of them, so a future, a go block and an agent can wait on each other. There's no parallelism: two fibers never run at the same moment, and a loop that never waits holds up everything else.
None of this exists on Windows or in the browser; neither has the coroutine support it needs. The examples on this page aren't live for that reason.
Futures and promises
(def total (future (Thread/sleep 100) (+ 1 2))) @total ;=> 3 (deref (future (Thread/sleep 1000) :slow) 50 :timeout) ;=> :timeout
A future that throws throws again when you deref it, wrapped in a java.util.concurrent.ExecutionException whose ex-cause is the original, as on the JVM. promise and deliver work as in Clojure.
core.async
clojure.core.async is the real API: channels, buffers, transducers on channels, go, <!, >!, alts! and timeout. It works like the ClojureScript version, with all the go blocks on one thread, but <!! and >!! work as well, because clove owns the main loop.
(require '[clojure.core.async :as a]) (let [done (a/chan 10)] (doseq [job ["fetch" "parse" "store"]] (a/go (a/<! (a/timeout (rand-int 50))) ; pretend to work (a/>! done job))) (repeatedly 3 #(a/<!! done))) ;=> ("fetch" "store" "parse"), in whatever order they finished
csp.clj is the same idea as a smaller library, and examples/csp-http-server.clj serves HTTP from go blocks.
Agents and refs
Agents run their actions in order, on a fiber of their own. Refs give you transactions: dosync retries when another fiber committed a change to a ref it read, and holds any agent sends until it commits.
(def balance (ref 100)) (def audit (agent [])) (dosync (alter balance - 30) (send audit conj [:withdraw 30])) (await audit) [@balance @audit] ;=> [70 [[:withdraw 30]]]
Coroutines
Everything above runs on three primitives, which you can use directly:
(def gen (coro/new (fn [] (coro/yield 1) (coro/yield 2) 3))) [(coro/resume gen) (coro/resume gen) (coro/resume gen)] ;=> [1 2 3]