Toby Hede
Toby Hede

Reputation: 37133

Idiomatic clojure conditionally calling a function

I have a clojure function that needs to push information into a map if a particular condition is true, using that map as a parameter for another function.

I have the following, but it feels clumsy with the repeated calls to the bar function.

(defn foo ([opts]

  (if (= true (something))       
    (bar (into opts {:a b}))
    (bar opts)))

(def bar [opts])

So if (something) is true, we push extra options into the opts parameter before calling the bar function, otherwise we just pass it through.

Upvotes: 4

Views: 3263

Answers (4)

Sebastian Oberhoff
Sebastian Oberhoff

Reputation: 1311

Note that since Clojure 1.5 this can be written

(cond-> opts (something) (merge {:a b}))

Upvotes: 2

KIMA
KIMA

Reputation: 1077

retief's answer is all right. It should be noted that if is an expression in Clojure instead of just a conditional construct. Therefore, it has a return value and you can use the return value as a parameter to functions:

(bar (if (something)       
        (into opts {:a b})
         opts))

You can think of it as the ternary operator in Java.

Upvotes: 2

Ankur
Ankur

Reputation: 33637

Refactor the conditional code into function(s). Something like:

(defn addAIfSomethig [opt] (if (something) (into opts {:a "A"}) opt) )
(defn addBIfSomethig [opt] (if (something) (into opts {:b "B"}) opt) )

Then in your function where you need to modify the opt before calling bar use function composition.

(defn foo [opt]
    (let [modifiers (comp addAIfSomethig addBIfSomethig)]
      (bar (modifiers opt))
    ))

Upvotes: 0

Retief
Retief

Reputation: 3217

First thing is that (= true (something)) can be replaced simply by (something) with no issues (unless you are actually trying to differentiate between a return value of true and a return value of, say, 1). If the options for the return value are true and false, (something) by itself will work fine. You can also use merge instead of into, which might be slightly clearer.

You could try

(bar (if (something)
       (merge opts {:a b})
       opts))

This would work as well, though it involves calling merge unnecessarily when (something) is false, though with nil for the second argument, merge should return very quickly.

(bar (merge opts
            (when (something)
              {:a b})))

Upvotes: 7

Related Questions