Default value in clojure maps
This is what the :or
key is used for when map destructuting.
(defn f [{:keys [title-1 title-2] :as opts
:or {title-1 "default-1" title-2 "default-2"}}]
(println opts)
(println title-1)
(println title-2))
which gives you
> (f {})
{}
default-1
default-2
nil
> (f {:title-1 "foo"})
{:title-1 foo}
foo
default-2
nil
> (f {:title-2 "bar"})
{:title-2 bar}
default-1
bar
nil
> (f {:title-1 "foo" :title-2 "bar"})
{:title-1 foo, :title-2 bar}
foo
bar
nil
A crucial difference between (or (:key hash) default)
and (:key hash default)
is the fact that the former evaluates default
only if it is necessary. In the latter case it is always evaluated. Therefore you should use or
if an evaluation of default
is expensive.
Another difference becomes apparent when your hash contains values which are false in a boolean context. In cases of such values (or (:key hash) default)
will be evaluated to default
instead of false
or nil
which you expect. In contrast to the or
expression, (:key hash default)
will yield correct results. As a side note, think twice before storing nil
as values in a hash.
Fine, those were the important differences. Now let's move to minor ones.
(or (:title opts) "Default title")
is expanded by the reader to
;; Redacted for the sake of brevity.
(let* [x (:title opts)]
(if x
x
"Default title"))
Arguably, it is less efficient than to simply evaluate
(:title opts "Default title")
Of course without any benchmarks it is hard to estimate the difference is speed, however I believe that it should be marginal.
On the other hand, at first glance (or (:key hash) :default)
seems to be easier to understand for someone not used to the (:key hash :default)
idiom. Consider programmers coming from other languages. In Ruby for instance the typical approach to handling a non existant element of a hash is
val = hash[:key] || :default
Hence, the first expression might be easier to parse by humans not accustomed to certain Clojure's idioms.