clj-kondo 2026-01-18

Might a linter that flags usage of (if (contains? #{:foo :bar} :baz) :a :b) could be rewritten as (if (#{:foo :bar} :baz) :a :b) be something to maybe consider?

I actually like contains? but this is because very early on in my first production use of Clojure a colleague told me he preferred it. I've been doing this since this day, even I know the latter alternative 😆

Are there any perf differences between the two?

I only recently learnt about it too (after reading some other Clojure code). I don't know if there is a performance difference.

I mean, I suggested (#{:foo :bar} :foo) to my colleague in 2013, but he preferred contains? since it was more explicit

I guess the difference is that the IFn call is the get equivalent

(#{:foo :bar} :foo)
:foo
and it doesn't always return a boolean

in CLJS this can be mean a small perf difference since you need a truth check

I see. I'm not much at all in the CLJS world.

I have been writing contains? too

cljs.user=> (str (fn [] (if (#{0 1} 0) true false)))
"function (){\nif(cljs.core.truth_(new cljs.core.PersistentHashSet(null, new cljs.core.PersistentArrayMap(null, 2, [(0),null,(1),null], null), null).call(null,(0)))){\nreturn true;\n} else {\nreturn false;\n}\n}"
cljs.user=> (str (fn [] (if (contains? #{0 1} 0) true false)))
"function (){\nif(cljs.core.contains_QMARK_.call(null,new cljs.core.PersistentHashSet(null, new cljs.core.PersistentArrayMap(null, 2, [(0),null,(1),null], null), null),(0))){\nreturn true;\n} else {\nreturn false;\n}\n}"

the truth check in the latter can be skipped since contains? always returns a boolean

Perhaps best then, to leave it. 🙂

There also seems to be an odd performance difference. I expected contains? to be faster in CLJS, but no:

cljs.user=> (time (let [x #{:a :b :c}] (dotimes [i 100000000] (if (contains? x :a) true false))))
"Elapsed time: 2829.361250 msecs"
nil
cljs.user=> (time (let [x #{:a :b :c}] (dotimes [i 100000000] (if (x :a) true false))))
"Elapsed time: 1504.274500 msecs"
nil

I guess because of some protocolesque call

anyway, it's not the same equivalent, so perhaps best to leave it

👍 1

Nil is a fun related case too

👍 2