Liking cljdoc? Tell your friends :D

dom-top.core

Unorthodox control flow.

Unorthodox control flow.
raw docstring

assert+cljmacro

(assert+ x)
(assert+ x message)
(assert+ x ex-type message)

Like Clojure assert, but throws customizable exceptions (by default, IllegalArgumentException), and returns the value it checks, instead of nil.

Clojure assertions are a little weird. Syntactically, they're a great candidate for runtime validation of state--making sure you got an int instead of a map, or that an object you looked up was present. However, they don't return the thing you pass them, which makes it a bit akward to use them in nested expressions. You typically have to do a let binding and then assert. So... let's return truthy values! Now you can

(assert+ (fetch-person-from-db :liu)
         "Couldn't fetch Liu!")

Moreover, Clojure assertions sensibly throw AssertionError. However, AssertionError is an error that "should never occur" and "a reasonable application should not try to catch." There are LOTS of cases where you DO expect assertions to fail sometimes and intend to catch them: for instance, validating user input, or bounds checks. So we're going to throw customizable exceptions.

Oh, and you can throw maps too. Those become ex-infos.

(assert+ (thing? that)
         {:type   :wasn't-a-thing
          :I'm    [:so :sorry]})
Like Clojure assert, but throws customizable exceptions (by default,
IllegalArgumentException), and returns the value it checks, instead of nil.

Clojure assertions are a little weird. Syntactically, they're a great
candidate for runtime validation of state--making sure you got an int instead
of a map, or that an object you looked up was present. However, they don't
*return* the thing you pass them, which makes it a bit akward to use them in
nested expressions. You typically have to do a let binding and then assert.
So... let's return truthy values! Now you can

    (assert+ (fetch-person-from-db :liu)
             "Couldn't fetch Liu!")

Moreover, Clojure assertions sensibly throw AssertionError. However,
AssertionError is an error that "should never occur" and "a reasonable
application should not try to catch." There are LOTS of cases where you DO
expect assertions to fail sometimes and intend to catch them: for instance,
validating user input, or bounds checks. So we're going to throw
customizable exceptions.

Oh, and you can throw maps too. Those become ex-infos.

    (assert+ (thing? that)
             {:type   :wasn't-a-thing
              :I'm    [:so :sorry]})
sourceraw docstring

bounded-futurecljmacro

(bounded-future & body)

Like future, but runs on the bounded agent executor. Useful for CPU-bound futures.

Like future, but runs on the bounded agent executor. Useful for CPU-bound
futures.
sourceraw docstring

bounded-future-callclj

(bounded-future-call f)

Like clojure.core/future-call, but runs on the bounded agent executor instead of the unbounded one. Useful for CPU-bound futures.

Like clojure.core/future-call, but runs on the bounded agent executor
instead of the unbounded one. Useful for CPU-bound futures.
sourceraw docstring

bounded-pmapclj

(bounded-pmap f coll)

Like pmap, but spawns tasks immediately, and uses the global bounded agent threadpool. Ideal for computationally bound tasks, especially when you might want to, say, pmap inside each of several parallel tasks without spawning eight gazillion threads.

Like pmap, but spawns tasks immediately, and uses the global bounded agent
threadpool. Ideal for computationally bound tasks, especially when you might
want to, say, pmap *inside* each of several parallel tasks without spawning
eight gazillion threads.
sourceraw docstring

disorderlycljmacro

(disorderly a)
(disorderly a b)
(disorderly a b & more)

This is a chaotic do expression. Like do, takes any number of forms. Where do evaluates forms in order, disorderly evaluates them in a random order. Where do returns the result of evaluating the final form, disorderly returns a sequence of the results of each form, in lexical (as opposed to execution) order, making it suitable for binding results.

This is particularly helpful when you want side effects, but you're not exactly sure how. Consider, for instance, testing that several mutations of an object all commute.

(disorderly (do (prn 1) :a)
            (do (prn 2) :b))

... prints either 1 then 2, or 2 then 1, but always returns (:a :b). Note that disorderly is not concurrent: branches evaluate in some order; it's just not a deterministic one.

This is a chaotic do expression. Like `do`, takes any number of forms. Where
`do` evaluates forms in order, `disorderly` evaluates them in a random order.
Where `do` returns the result of evaluating the final form, `disorderly`
returns a sequence of the results of each form, in lexical (as opposed to
execution) order, making it suitable for binding results.

This is particularly helpful when you want side effects, but you're not
exactly sure how. Consider, for instance, testing that several mutations of
an object all commute.

    (disorderly (do (prn 1) :a)
                (do (prn 2) :b))

... prints either 1 then 2, or 2 then 1, but always returns (:a :b). Note
that `disorderly` is *not* concurrent: branches evaluate in some order; it's
just not a deterministic one.
sourceraw docstring

fcatchclj

(fcatch f)

Takes a function and returns a version of it which returns, rather than throws, exceptions.

; returns RuntimeException
((fcatch #(throw (RuntimeException. "hi"))))
Takes a function and returns a version of it which returns, rather than
throws, exceptions.

    ; returns RuntimeException
    ((fcatch #(throw (RuntimeException. "hi"))))
sourceraw docstring

letrcljmacro

(letr bindings & body)

Let bindings, plus early return.

You want to do some complicated, multi-stage operation assigning lots of variables--but at different points in the let binding, you need to perform some conditional check to make sure you can proceed to the next step. Ordinarily, you'd intersperse let and if statements, like so:

(let [res (network-call)]
  (if-not (:ok? res)
    :failed-network-call

    (let [people (:people (:body res))]
      (if (zero? (count people))
        :no-people

        (let [res2 (network-call-2 people)]
          ...

This is a linear chain of operations, but we're forced to nest deeply because we have no early-return construct. In ruby, we might write

res = network_call
return :failed_network_call if not x.ok?

people = res[:body][:people]
return :no-people if people.empty?

res2 = network_call_2 people
...

which reads the same, but requires no nesting thanks to Ruby's early return. Clojure's single-return is usually a boon to understandability, but deep linear branching usually means something like

  • Deep nesting (readability issues)
  • Function chaining (lots of arguments for bound variables)
  • Throw/catch (awkward exception wrappers)
  • Monadic interpreter (slow, indirect)

This macro lets you write:

(letr [res    (network-call)
       _      (when-not (:ok? res) (return :failed-network-call))
       people (:people (:body res))
       _      (when (zero? (count people)) (return :no-people))
       res2   (network-call-2 people)]
  ...)

letr works like let, but if (return x) is ever returned from a binding, letr returns x, and does not evaluate subsequent expressions.

If something other than (return x) is returned from evaluating a binding, letr binds the corresponding variable as normal. Here, we use _ to indicate that we're not using the results of (when ...), but this is not mandatory. You cannot use a destructuring bind for a return expression.

letr is not a true early return--(return x) must be a terminal expression for it to work--like (recur). For example,

(letr [x (do (return 2) 1)]
  x)

returns 1, not 2, because (return 2) was not the terminal expression. Someone clever should fix this.

(return ...) only works within letr's bindings, not its body.

Let bindings, plus early return.

You want to do some complicated, multi-stage operation assigning lots of
variables--but at different points in the let binding, you need to perform
some conditional check to make sure you can proceed to the next step.
Ordinarily, you'd intersperse let and if statements, like so:

    (let [res (network-call)]
      (if-not (:ok? res)
        :failed-network-call

        (let [people (:people (:body res))]
          (if (zero? (count people))
            :no-people

            (let [res2 (network-call-2 people)]
              ...

This is a linear chain of operations, but we're forced to nest deeply because
we have no early-return construct. In ruby, we might write

    res = network_call
    return :failed_network_call if not x.ok?

    people = res[:body][:people]
    return :no-people if people.empty?

    res2 = network_call_2 people
    ...

which reads the same, but requires no nesting thanks to Ruby's early return.
Clojure's single-return is *usually* a boon to understandability, but deep
linear branching usually means something like

- Deep nesting         (readability issues)
- Function chaining    (lots of arguments for bound variables)
- Throw/catch          (awkward exception wrappers)
- Monadic interpreter  (slow, indirect)

This macro lets you write:

    (letr [res    (network-call)
           _      (when-not (:ok? res) (return :failed-network-call))
           people (:people (:body res))
           _      (when (zero? (count people)) (return :no-people))
           res2   (network-call-2 people)]
      ...)

letr works like let, but if (return x) is ever returned from a binding, letr
returns x, and does not evaluate subsequent expressions.

If something other than (return x) is returned from evaluating a binding,
letr binds the corresponding variable as normal. Here, we use _ to indicate
that we're not using the results of (when ...), but this is not mandatory.
You cannot use a destructuring bind for a return expression.

letr is not a *true* early return--(return x) must be a *terminal* expression
for it to work--like (recur). For example,

    (letr [x (do (return 2) 1)]
      x)

returns 1, not 2, because (return 2) was not the terminal expression. Someone
clever should fix this.

(return ...) only works within letr's bindings, not its body.
sourceraw docstring

letr-let-ifclj

(letr-let-if groups body)

Takes a sequence of binding groups and a body expression, and emits a let for the first group, an if statement checking for a return, and recurses; ending with body.

Takes a sequence of binding groups and a body expression, and emits a let
for the first group, an if statement checking for a return, and recurses;
ending with body.
sourceraw docstring

letr-partition-bindingsclj

(letr-partition-bindings bindings)

Takes a vector of bindings [sym expr, sym' expr, ...]. Returns binding-groups: a sequence of vectors of bindgs, where the final binding in each group has an early return. The final group (possibly empty!) contains no early return.

Takes a vector of bindings [sym expr, sym' expr, ...]. Returns
binding-groups: a sequence of vectors of bindgs, where the final binding in
each group has an early return. The final group (possibly empty!) contains no
early return.
sourceraw docstring

letr-rewrite-returnclj

(letr-rewrite-return expr)

Rewrites (return x) to (Return. x) in expr. Returns a pair of [changed? expr], where changed is whether the expression contained a return.

Rewrites (return x) to (Return. x) in expr. Returns a pair of [changed?
expr], where changed is whether the expression contained a return.
sourceraw docstring

real-pmapclj

(real-pmap f coll)

Like pmap, but spawns tasks immediately, and launches real Threads instead of using a bounded threadpool. Useful when your tasks might block on each other, and you don't want to deadlock by exhausting the default clojure worker threadpool halfway through the collection. For instance,

(let [n 1000
      b (CyclicBarrier. n)]
  (pmap (fn [i] [i (.await b)]) (range n)))

... deadlocks, but replacing pmap with real-pmap works fine.

If any thread throws an exception, all mapping threads are interrupted, and the original exception is rethrown. This prevents deadlock issues where mapping threads synchronize on some resource (like a cyclicbarrier or countdownlatch), but one crashes, causing other threads to block indefinitely on the barrier. Note that we do not include a ConcurrentExecutionException wrapper.

All pmap threads should terminate before real-pmap returns or throws. This prevents race conditions where mapping threads continue doing work concurrently with, say, clean-up code intended to run after the call to (pmap).

If the thread calling (pmap) itself is interrupted, all bets are off.

Like pmap, but spawns tasks immediately, and launches real Threads instead
of using a bounded threadpool. Useful when your tasks might block on each
other, and you don't want to deadlock by exhausting the default clojure
worker threadpool halfway through the collection. For instance,

    (let [n 1000
          b (CyclicBarrier. n)]
      (pmap (fn [i] [i (.await b)]) (range n)))

... deadlocks, but replacing `pmap` with `real-pmap` works fine.

If any thread throws an exception, all mapping threads are interrupted, and
the original exception is rethrown. This prevents deadlock issues where
mapping threads synchronize on some resource (like a cyclicbarrier or
countdownlatch), but one crashes, causing other threads to block indefinitely
on the barrier. Note that we do not include a ConcurrentExecutionException
wrapper.

All pmap threads should terminate before real-pmap returns or throws. This
prevents race conditions where mapping threads continue doing work
concurrently with, say, clean-up code intended to run after the call to
(pmap).

If the thread calling (pmap) itself is interrupted, all bets are off.
sourceraw docstring

real-pmap-helperclj

(real-pmap-helper f coll)

Helper for real-pmap. Maps f over coll, collecting results and exceptions. Returns a tuple of [results, exceptions], where results is a sequence of results from calling f on each element (nil if f throws); and exceptions is a sequence of exceptions thrown by f, in roughly time order.

Helper for real-pmap. Maps f over coll, collecting results and exceptions.
Returns a tuple of [results, exceptions], where results is a sequence of
results from calling `f` on each element (`nil` if f throws); and exceptions
is a sequence of exceptions thrown by f, in roughly time order.
sourceraw docstring

with-retrycljmacro

(with-retry initial-bindings & body)

It's really fucking inconvenient not being able to recur from within (catch) expressions. This macro wraps its body in a (loop [bindings] (try ...)). Provides a (retry & new bindings) form which is usable within (catch) blocks: when this form is returned by the body, the body will be retried with the new bindings. For instance,

(with-retry [attempts 5]
  (network-request...)
  (catch RequestFailed e
    (if (< 1 attempts)
      (retry (dec attempts))
      (throw e))))
It's really fucking inconvenient not being able to recur from within (catch)
expressions. This macro wraps its body in a (loop [bindings] (try ...)).
Provides a (retry & new bindings) form which is usable within (catch) blocks:
when this form is returned by the body, the body will be retried with the new
bindings. For instance,

    (with-retry [attempts 5]
      (network-request...)
      (catch RequestFailed e
        (if (< 1 attempts)
          (retry (dec attempts))
          (throw e))))
sourceraw docstring

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close