19

I want to supply a default value which can be overridden. I know I can use a ternary, like this:

(def foo (if (not (nil? bar)) bar baz))

But surely there is a more idiomatic way in Clojure to say "use bar, or baz if bar is nil.

Any suggestions?

Josh Glover
  • 25,142
  • 27
  • 92
  • 129

3 Answers3

33

This will assign bar unless it is nil or false, and baz otherwise.

(def foo (or bar baz))

EDIT

If you wish to check for nil precisely, you can slightly optimize your original code, like this:

(def foo (if (nil? bar) baz bar))

I believe, this is the shortest possible way, though not idiomatic.

bereal
  • 32,519
  • 6
  • 58
  • 104
  • This is great, and will solve the problem that I'm facing in my code, but I'd also like to know the idiom for differentiating `nil` and `false` when doing this. – Josh Glover Apr 14 '12 at 08:27
  • 1
    @JoshGlover Well, I'm not sure if there is a special idiom for that, but if you exchange `bar` and `baz`, like `(if (nil? bar) baz bar))`, you will get rid of `not`, and it's hardly getting any shorter. – bereal Apr 14 '12 at 08:32
  • Good point, and very nice indeed. Thanks! If you update your answer to show this way as well, I'll accept it. – Josh Glover Apr 14 '12 at 08:43
4

Your question doesn't specifically ask about multiple vars, but if you did want this defaulting for more than one var the idiomatic way to do it is to use destructuring on map with :or defaults.

e.g. Take this function that takes a map argument m, the expected map has keys of :a, :b, & :c but if :b and/or :c are not supplied then the defaults are taken from the :or clause

(defn foo [m]
    (let [{:keys [a b c], :or {b 100 c 200}} m]
      (println "a:" a)
      (println "b:" b)
      (println "c:" c)))

user> (foo {:a 1 :b 2})
a: 1   ; no default, use supplied value
b: 2   ; value supplied, default ignored
c: 200 ; no value supplied, use default from :or
nil
sw1nn
  • 7,278
  • 1
  • 26
  • 36
2

fnil is also an option:

user> (def default-to (partial fnil identity))
#'user/default-to

user> (let [bar :foo
            baz :default]
        ((default-to baz) bar))
:foo

user> (let [bar nil
            baz :default]
        ((default-to baz) bar))
:default
Brian Carper
  • 71,150
  • 28
  • 166
  • 168