Idiomatic empty?

Hello,
I’ve seen that it is not idiomatic to use the empty? predicate and better use seq but I’d like to understand why. For me, it is much more clear (easy to understand) to read something like :

(when-not (empty? x) ...)

…than…

(when (seq x) ...)

First one reads like plain english, where the second one doesn’t and needs a tiny little bit more of knowledge about the seq function. This is for me also strange that the docstring of the empty? function recommends … to not use the empty? function and prefer seq instead. Is it to save one function call ? … Then why not recomend to use (not (even? ..)) instead of odd?.

As a beginner I put a lot of effort in trying to write clean and understandable code with Clojure, and the case of the empty? function stays like a ‘grain of sand’ I’d like to get rid of.

Hopefully someone here will be able to help clarify.

Thanks

2 Likes

I assume the encouragement to use seq over empty? is from efficiency

The source code of empty? calls seq on the collection and inverts the boolean result

(not (seq coll)))

There seems to be an expectation that the Clojure developer would understand seq function and choose that as the preferred approach.

Personally I find empty? more readable and one less thing to parse.

If the code path that uses empty? is a performance bottleneck then is a small optimisation to make.

This is probably a minority view though

4 Likes

First one reads like plain english

Clojure doesn’t try to make source code readable like prose. I would definitely recommend against skewing towards “reads like plain English” approaches, lest you end up with Python’s 1 if True else 2. :slight_smile:

Is it to save one function call ?

It’s to avoid an extra not. (empty? x) is (not (seq x)), so (not (empty? x)) is (not (not (seq x))).
(not (even? ...)) is already what odd? itself does.

I put a lot of effort in trying to write clean and understandable code with Clojure

When you get the “tiny little bit more of knowledge about the seq function” that you’ve mentioned, (when (seq ...) ...) becomes cleaner than (when (not (empty? ...)) ...).

All in all, it’s an idiom. Just like “it rains cats and dogs” in English. It might not make sense to a newcomer, but it does make sense to the active users of the language, especially if you consider historical context.

5 Likes

I pretty much always use not-empty instead of seq myself (source). I’ll consider switching all my not-emptys over to seqs after I replace all my ->>s with transducers.

3 Likes

It’s worth noting that seq and not-empty are not equivalent.

(seq s) produces a Seq or nil (or throws if s is not seqable?)

(not-empty s) produces s or nil (or throws)

(seq "Hello") => (\H \e \l \l \o)

(not-empty "Hello") => "Hello"

Perhaps you meant (not (empty? s))

4 Likes

I should’ve specified that I meant in the context of conditionals. seq and not-empty have equivalently truthy return values.

(Though as an aside, even outside of conditionals I don’t think I’ve ever used seq :man_shrugging:)

1 Like

Thanks all, it really helps me clarify :+1:

I want to note one thing that’s only been alluded to so far. In English and most programming languages, there isn’t a single word for “non-empty sequence”. There’s that phrase, but it’s built on the negative, on stating what the object isn’t, and most programming languages match it (if x.len != 0 {…}).

seq is a name that means/represents “non-empty sequence”. It gives the ability to say conversationally, “if this is a seq, then we can do x.” It is a name with positive meaning. I think this is incredibly powerful.

7 Likes