4 ms·
> prefer (not (empty? coll)) over (seq coll), There's a reason why (seq coll) is a standard Clojure idiom, which the source for empty? reveals: (defn empt
by dghf 9y ago
> prefer (not (empty? coll)) over (seq coll),
There's a reason why (seq coll) is a standard Clojure idiom, which the source for empty? reveals:
(defn empty?
"Returns true if coll has no items - same as (not (seq coll)).
Please use the idiom (seq x) rather than (not (empty? x))"
{:added "1.0"
:static true}
[coll] (not (seq coll)))
By using (not (empty? coll)), you are effectively writing (not (not (seq coll))), which isn't really very elegant, even if of marginal significance performance-wise.
Curiously, he later champions the use of (some? x) rather than the arguably more readable (not (nil? x)), even though in this case the former is directly equivalent to the latter:
(defn some?
"Returns true if x is not nil, false otherwise."
{:tag Boolean
:added "1.6"
:static true}
[x] (not (nil? x)))
> correct, error-proof way to choose "first non-nil value"
(cond
(some? a) a
(some? b) b
(some? c) c)
I'm sorry, but that's horrible. What if you had 20 items to check? Or an indeterminate number?
How about:
(first (remove nil? [a b c]))
- lambdadmitry 9y agoThe way empty? is implemented is literally an implementation detail, so it's somewhat irrelevant to the discussion of readability. Regarding the last example: I would say (->> [a b c] (remove nil?) first) is even better. However, if that vector is effectively a tuple (so a, b, and c are heterogenous and can be named), cond is more explicit and readable.
- dghf 9y ago> However, if that vector is effectively a tuple (so a, b, and c are heterogenous and can be named), cond is more explicit and readable. I don't understand. Could you illustrate with an example?
- lambdadmitry 9y agoSorry, I forgot the original snippet and though about something else (working over sequences). However, in the original context it makes even more sense to use cond as the number of variables is clearly limited (and they probably have meaningful names).
- dghf 9y ago> However, in the original context it makes even more sense to use cond as the number of variables is clearly limited (and they probably have meaningful names). But the construct with remove and first can be applied to a limited number of variables with meaningful names just as easily as the cond construct. Plus it has these advantages: - It's shorter. - It avoids jarring repetition. - It's more readable, I'd argue, than the cond version: in the threading-macro version you offered, it translates directly into English as "take a sequence, strip out the nil values, and return the first item of what's left". - It can be applied equally in situations where the number of items is known at compile time, and those where it isn't. - It can be applied to an arbitrarily large number of items.
- escherize 9y agoMust say I prefer or for this, and consider differentiating false and nil to usually be a code smell: (or a b c)
- dghf 9y agoThe relevant bit of the article was explicitly concerned with situations where false values needed to be returned if present, and ruled out the use of or for precisely that reason. But I agree: if you were ever in a position where you needed to do this, you might want to reconsider how you were representing your data.