Email or username:

Password:

Forgot your password?
Arne Brasseur

Little Clojure tip: name sets as if they are predicates (where appropriate).

In Clojure it's quite common to use sets as functions (it acts as a function that tests membership).

(some #{a} coll)
(filter (comp #{1 2 3} :id) coll)

This is idiomatic, if you've done a bit of Clojure you will read this easily, because they are set literals it's quite obvious. But if the set is defined somewhere else, then suddenly it gets a lot less obvious.

(def admin-ids #{53 65 78})

(when (admin-ids (:id user)) ,,,)

In this case I would probably use an explicit contains?, at least that shows that it has to be a set or map.

(when (contains? admin-ids (:id user)) ,,,)

But you can also name the var as if it's a function

(def admin-id? #{53 65 78})
(when (admin-id? (:id user)) ,,,)

And this way you could refactor this later to actually be a function, e.g. something that checks the database.

#clojure

10 comments
Chip Butty

@plexus I'm a bit torn there as I often use sorted-sets as lists (like a vector I ran distinct on). I do also use them as predicates. I think the naming depends on what I think I'm going to use them for, which isn't necessarily great.

Arne Brasseur

@otfrom I think it does depend on what you're using it for, and I think that's fine. That's also why I said "where appropriate".

I think naming them as a function/predicate means that you're conceptually thinking of them as a function, it just happens to be implemented as a simple membership check at the moment.

The same can also apply to maps.

Josh Kingsley

@plexus I tend to only use sets as functions when itโ€™s a set literal or otherwise very obvious that the value is a set. contains? makes it much more readable in most cases IMO

Mikko Koski ๐Ÿ‡ซ๐Ÿ‡ฎ

@plexus Isn't there quite strong concensus that functions ending in question mark should return boolean? Sets return the item, which isn't boolean, necessarily.

Arne Brasseur

@rap1ds is there? I think the only concensus is that it's generally a predicate, so output should be truthy/falsy.

Mikko Koski ๐Ÿ‡ซ๐Ÿ‡ฎ

@plexus I read this from Clojure FAQ โ€œMore specifically, a trailing ? indicates that a predicate strictly returns a boolean result (true or false)โ€ clojure.org/guides/faq#qmark_b

russ

@plexus an interesting idea! I love sets as functions to the point where i hardly use `=` anymore.

Arne Brasseur

@russmatney it's so much more flexible and clear, compare:

#(or (= :test (:env %)) (= :dev (:env %))
(comp #{:test :dev} :env)
russ

@plexus yep! Especially for multiple values as you showed. I love forms like this that make things easier to change (adding another value to this set literal vs another whole equality fn call)

Go Up