Cond-> macro - use output in conditions

Hi Everybody,

The easiest way to explain what I’d like to do is an example.

This works:

(cond-> {:is-valid true :foo "foo"} (= 1 1) (assoc :bar "bar"))
; {:is-valid true, :foo "foo", :bar "bar"}

But this doesn’t:

(cond-> {:is-valid true :foo "foo"} (:is-valid this) (assoc :bar "bar"))
; Syntax error compiling at (REPL:1:31).
; Unable to resolve symbol: this in this context

Please advise is the output itself bound into some symbol (like this in my example) so I can use it?

Thank you.

Best regards,

Billy

No, the condition stands alone and the value is not threaded through it.

At work we have a condp-> macro that threads the value through both the condition and the expression: commons/extensions.clj at master · worldsingles/commons (github.com)

You’re almost there. With cond->, you’d have to put it in something like a let:

(let [x {:is-valid true :foo "foo"}]
  (cond-> x
   (:is-valid x) (assoc :bar "bar")))

If you’re willing to tweak the macro though… @seancorfield beat me to it :slight_smile:

Is there a ask.clojure.org issue about including a similar macro in core? I feel it comes up very often on the slack and forums, just as much as update-vals does, at least in my unscientific observation.

Not as far as I know (re: ask).

As an experience report, I will say that we have less than 30 uses of condp-> (in 119K lines of Clojure) and zero uses of condp->>. Compare that with 385 uses of the built-in cond-> and 17 uses of cond->>. We are less enamored with condp-> in practice than we thought we’d be – so I suspect it’s much less requested than you might think :slight_smile:

We have 39 uses of as-> in that codebase too. We use some-> and some->> a lot more than even the built-in cond-arrows: 447 uses of some-> and 43 uses of some->>.

Mark Engelberg offered a souped-up cond and a good rationale ([CLJ-200] Extend cond to support inline let, much like for - JIRA), but it is currently catalogued as “declined”. I think it or something similar became the germ of the “better-cond” library, https://github.com/Engelberg/better-cond.

I wonder how many times you’ve used let where you would normally use ->/cond-> because a single output from a single function needed destructuring.

Threading macros are great when the use case is simple enough but let gives ultimate flexibility and in my opinion easier readability/maintainability for more complicated use cases.