Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
Check for round-about clojure.string/join
.
; avoid
(apply str x)
; prefer
(clojure.string/join x)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
Check for round-about clojure.string/join
.
; avoid
(apply str (interpose "," x))
; prefer
(clojure.string/join "," x)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
Check for round-about clojure.string/reverse
.
; avoid
(apply str (reverse x))
; prefer
(clojure.string/reverse x)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
Layering assoc
calls are hard to read. assoc-in
is known and idiomatic.
; avoid
(assoc coll :key1 (assoc (:key2 coll) :key2 new-val))
(assoc coll :key1 (assoc (coll :key2) :key2 new-val))
(assoc coll :key1 (assoc (get coll :key2) :key2 new-val))
; prefer
(assoc-in coll [:key1 :key2] new-val)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 0.1.85 |
It's nice when the default branch is consistent.
; avoid
(cond
(< 10 num) (println 10)
(< 5 num) (println 5)
true (println 0))
; prefer
(cond
(< 10 num) (println 10)
(< 5 num) (println 5)
:else (println 0))
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
vector
is succinct and meaningful.
; avoid
(conj [] :a b {:c 1})
; prefer
(vector :a b {:c 1})
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 1.0 | 1.0 |
(defn [])
is preferable over (def (fn []))
. Extrapolate to closures.
; avoid
(def check-inclusion
(let [allowed #{:a :b :c}]
(fn [i] (contains? allowed i))))
; prefer
(let [allowed #{:a :b :c}]
(defn check-inclusion [i]
(contains? allowed i)))
; avoid
(def some-func
(fn [i] (+ i 100)))
; prefer
(defn some-func [i]
(+ i 100))
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
false?
exists so use it.
; avoid
(= false x)
(= x false)
; prefer
(false? x)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
nil?
exists so use it.
; avoid
(= nil x)
(= x nil)
; prefer
(nil? x)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
true?
exists so use it.
; avoid
(= true x)
(= x true)
; prefer
(true? x)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
zero?
exists so use it.
; avoid
(= 0 num)
(= num 0)
(== 0 num)
(== num 0)
; prefer
(zero? num)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
Check for (filter (complement pred) coll)
.
; avoid
(filter (complement even?) coll)
; prefer
(remove even? coll)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
filterv is preferable for using transients.
; avoid
(vec (filter pred coll))
; prefer
(filterv pred coll)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
ffirst is succinct and meaningful.
; avoid
(first (first coll))
; prefer
(ffirst coll)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
fnext
is succinct and meaningful.
; avoid
(first (next coll))
; prefer
(fnext coll)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 1.15.0 | 1.15.0 |
clojure.test/is
expects =
-based assertions to put the expected value first.
This rule uses two checks on the =
call to determine if it should issue a diagnostic:
; avoid
(is (= status 200))
(is (= (my-plus 1 2) 3))
; prefer
(is (= 200 status))
(is (= 3 (my-plus 1 2)))
; non-issues
(is (= (hash-map :a 1) {:a 1}))
(is (= (hash-set :a 1) #{:a 1}))
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
let
has an implicit do
, so use it.
; avoid
(let [a 1 b 2] (do (println a) (println b)))
; prefer
(let [a 1 b 2] (println a) (println b))
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
Check for (apply concat (apply map x y))
.
; avoid
(apply concat (apply map x y))
; prefer
(mapcat x y)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
Check for (apply concat (map x y z))
.
; avoid
(apply concat (map x y))
(apply concat (map x y z))
; prefer
(mapcat x y)
(mapcat x y z)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
Checks for simple -1 that should use clojure.core/dec
.
; avoid
(- x 1)
; prefer
(dec x)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
Checks for x - 0.
; avoid
(- x 0)
; prefer
x
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 1.3.0 | 1.3.0 |
Sort the arities of a function from fewest to most arguments.
; avoid
(defn foo
([x] (foo x 1))
([x y & more] (reduce foo (+ x y) more))
([x y] (+ x y)))
; prefer
(defn foo
([x] (foo x 1))
([x y] (+ x y))
([x y & more] (reduce foo (+ x y) more)))
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
Checks for (* x 1).
; avoid
(* x 1)
(* 1 x)
; prefer
x
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
Checks for (* x 0).
; avoid
(* x 0)
(* 0 x)
; prefer
0
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
neg?
exists so use it.
; avoid
(< num 0)
(> 0 num)
; prefer
(neg? num)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
Checks for simple nested additions.
; avoid
(+ x (+ y z))
(+ x (+ y z a))
; prefer
(+ x y z)
(+ x y z a)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
Checks for simple nested multiply.
; avoid
(* x (* y z))
(* x (* y z a))
; prefer
(* x y z)
(* x y z a)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1.69 | 1.15.2 |
new
special form is discouraged for dot usage.
; avoid
(new java.util.ArrayList 100)
; prefer (chosen style :dot (default))
(java.util.ArrayList. 100)
; prefer (chosen style :method-value, requires clojure version 1.12+)
(java.util.ArrayList/new 100)
Name | Default | Options |
---|---|---|
:chosen-style | :dot | :dot , :method-value |
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
nfirst is succinct and meaningful.
; avoid
(next (first coll))
; prefer
(nfirst coll)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
nnext is succinct and meaningful.
; avoid
(next (next coll))
; prefer
(nnext coll)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
not=
exists, so use it.
; avoid
(not (= num1 num2))
; prefer
(not= num1 num2)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
some?
exists so use it.
; avoid
(not (nil? x))
; prefer
(some? x)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
not-any? is succinct and meaningful.
; avoid
(not (some even? coll))
; prefer
(not-any? even? coll)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
Checks for simple +1 that should use clojure.core/inc
.
; avoid
(+ x 1)
(+ 1 x)
; prefer
(inc x)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
Checks for x + 0.
; avoid
(+ x 0)
(+ 0 x)
; prefer
x
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
pos?
exists so use it.
; avoid
(< 0 num)
(> num 0)
; prefer
(pos? num)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1.69 | 0.1.69 |
Use boolean
if you must return true
or false
from an expression.
; avoid
(if some-val true false)
(if (some-func) true false)
; prefer
(boolean some-val)
(boolean (some-func))
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1.69 | 0.1.69 |
NOTE: Requires Clojure version 1.11.0.
Prefer clojure.math to interop.
; avoid
Math/PI
(Math/atan 45)
; prefer
clojure.math/PI
(clojure.math/atan 45)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 1.9.0 | 1.9.0 |
Prefer clojure.string to interop.
method | clojure.string |
---|---|
.contains | clojure.string/includes? |
.endsWith | clojure.string/ends-with? |
.replace | clojure.string/replace |
.split | clojure.string/split |
.startsWith | clojure.string/starts-with? |
.toLowerCase | clojure.string/lower-case |
.toUpperCase | clojure.string/upper-case |
.trim | clojure.string/trim |
; avoid
(.toUpperCase "hello world")
; prefer
(clojure.string/upper-case "hello world")
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1.69 | 1.0 |
cond
checking against the same value in every branch is a code smell.
This rule uses the first test-expr as the template to compare against each other test-expr. It has a number of conditions it checks as it runs:
cond
is well-formed (aka even number of args).cond
has more than 1 pair.true
or a keyword.Provided all of that is true, then the middle arguments of the test-exprs are
gathered and rendered into a condp
.
; avoid
(cond
(= 1 x) :one
(= 2 x) :two
(= 3 x) :three
(= 4 x) :four)
; prefer
(condp = x
1 :one
2 :two
3 :three
4 :four)
; avoid
(cond
(= 1 x) :one
(= 2 x) :two
(= 3 x) :three
:else :big)
; prefer
(condp = x
1 :one
2 :two
3 :three
:big)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 1.15.0 | 1.15.0 |
The core builder functions are helpful when creating an object from an opaque sequence, but are much less readable when used in maps to get around issues with anonymous function syntax peculiarities.
; avoid
(map #(hash-map :a 1 :b %) (range 10))
; prefer
(for [item (range 10)] {:a 1 :b item})
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 0.1.69 |
vary-meta
works like swap!
, so no need to access and overwrite in two steps.
; avoid
(with-meta x (assoc (meta x) :filename filename))
; prefer
(vary-meta x assoc :filename filename)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 1.11 | 1.11 |
reduce
calls the provided function on every element in the provided
collection. Because of how str
is implemented, a new string is created
every time it's called. Better to rely on clojure.string/join
's efficient
StringBuilder and collection traversal.
Additionally, the 2-arity form of reduce
returns the first item without
calling str
on it if it only has one item total, which is
generally not what is expected when calling str
on something.
; avoid
(reduce str x)
(reduce str "" x)
; prefer
(clojure.string/join x)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1.69 | 0.1.69 |
Directly nested lets can be merged into a single let block.
; avoid
(let [a 1]
(let [b 2]
(println a b)))
(let [a 1
b 2]
(println a b))
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 1.10.0 | 1.10.0 |
Clojure regex literals (#"") are passed to java.util.regex.Pattern/compile
at read time. re-pattern
checks if the given arg is a Pattern, making it a no-op when given a regex literal.
; avoid
(re-pattern #".*")
; prefer
#".*"
Enabled by default | Version Added | Version Updated |
---|---|---|
false | 0.1.119 | 1.11 |
Sets can be used as functions and they're converted to static items when they contain constants, making them fairly fast. However, they're not as fast as [[case]] and their meaning is less clear at first glance.
; avoid
(#{'a 'b 'c} elem)
; prefer
(case elem (a b c) elem nil)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1.69 | 0.1.69 |
assoc-in
loops over the args, calling assoc
for each key. If given a single key,
just call assoc
directly instead for performance and readability improvements.
; avoid
(assoc-in coll [:k] 10)
; prefer
(assoc coll :k 10)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
Convert (.toString)
to (str)
.
; avoid
(.toString x)
; prefer
(str x)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 1.11 | 1.11 |
for
is a complex and weighty macro. When simply applying a function to each element, better to rely on other built-ins.
; avoid
(for [item items]
(f item))
; prefer
(map f items)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
update-in
-ing an assoc
with the same key are hard to read. assoc-in
is known
and idiomatic.
; avoid
(update-in coll [:a :b] assoc 5)
; prefer
(assoc-in coll [:a :b] 5)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1.69 | 1.2.0 |
A single item in a do
is a no-op. However, it is sometimes necessary to wrap expressions in do
s to avoid issues, so do
surrounding ~@something
will be skipped as well as #(do something)
.
; avoid
(do coll)
; prefer
coll
; skipped
(do ~@body)
#(do [%1 %2])
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1.69 | 1.2.0 |
when
already defines an implicit do
. Rely on it.
; avoid
(when x (do (println :a) (println :b) :c))
; prefer
(when x (println :a) (println :b) :c)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
when-not
exists so use it lol.
; avoid
(when (not x) :a :b :c)
; prefer
(when-not x :a :b :c)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
when-not
already defines an implicit do
. Rely on it.
; avoid
(when-not x (do (println :a) (println :b) :c))
; prefer
(when-not x (println :a) (println :b) :c)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 0.1.69 |
seq
returns nil
when given an empty collection. empty?
is implemented as
(not (seq coll))
so it's best and fastest to use seq
directly.
; avoid
(when-not (empty? ?x) &&. ?y)
; prefer
(when (seq ?x) &&. ?y)
Enabled by default | Version Added | Version Updated |
---|---|---|
true | 0.1 | 1.2.0 |
Two not
s cancel each other out.
; avoid
(when-not (not x) y z)
; prefer
(when x y z)
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close