3 ms·
> My (incomplete) set of personal rules: > - use contains? instead of using sets as functions, [snip] > An example. To understand this piece of code you need
by dghf 9y ago
> My (incomplete) set of personal rules:
> - use contains? instead of using sets as functions,
[snip]
> An example. To understand this piece of code you need to know that possible-states is a set:
(when (possible-states state)
... )
> By contrast, to understand following code you don’t need any context:
(when (contains? possible-states state)
... )
I disagree. In the first example, it's clear from context that possible-states is a function (to be precise, an object that implements IFn) that returns a truthy or falsy value depending on the value of state; the name possible-states suggests it's checking that the value of state is valid, according to some criteria.
To determine what those criteria are, you'd have to look at the definition of possible-states: but that would also be true even if you used the more verbose contains? construct.
By not using contains?, you also retain the option to replace possible-states with an actual function, should you later discover you need further validation or processing not possible with a simple set.
For example, if state is a text string, and you find out further down the line that sometimes it's in the wrong case or has unwanted leading or trailing white space, you can replace
(def possible-states #{"foo" "bar" "baz"})
with
(defn possible-states [state]
(->> state
clojure.string/trim
clojure.string/lower-case
#{"foo" "bar" "baz"}))
without needing to change code elsewhere.
Even if you don't feel that this flexibility is worth the ambiguity, contains? offers little comfort, as it can take many things other than a set:
(contains? #{"foo"} "foo") ; true
(contains? {"foo" 1} "foo") ; true ("foo" is a key of the map)
(contains? {:bar "foo"} "foo") ; false ("foo" is a value but not a key)
(contains? ["foo" "bar"] 1) ; true (vectors are keyed by integers)
(contains? '("foo" "bar") 1) ; false (but lists aren't)
(contains? "foo" 1) ; true (but strings are)