Clojure: rest vs. next

It's easy if you have this:

(next '(1))
=> nil

So next looks at the next thing and if the line is empty it returns nil instead of an empty seq. This means that it needs to look ahead (to the first item it would return) which makes it not fully lazy (maybe you don't need the next value, but next wastes the compute time to look ahead).

(rest '(1))
=> ()

rest doesn't look ahead and just returns the rest of the seq.

Maybe you think, Why even bother using two different things here? The reason is that you normally want to know if there is nothing left in the seq and just return nil, but in some cases where performance is very important and evaluating one more item could mean tremendous effort you can use rest.


I now prefer to use next with recursion, as the escape-evaluation is simpler/cleaner:

(loop [lst a-list]
    (when lst
        (recur (next lst))

vs

(loop [lst a-list]
    (when-not (empty? lst)   ;; or (when (seq? lst)
        (recur (rest lst))

A case for using rest, though, would be if you use a collection as a queue or stack. In that case you want your function to return an empty collection when popping or dequeueing the last item.


next is like (seq (rest ...)).

rest will return the remaining piece of a sequence. If that piece of the sequence has not yet been realized, rest doesn't force it. It won't even tell you if there are more elements left in the sequence.

next does the same thing but then forces at least one element of the sequence to be realized. So if next returns nil, you know there aren't any more elements left in the sequence.


As the page you linked described, next is stricter than (the new behaviour of) rest because it needs to evaluate the structure of the lazy cons to know whether to return nil or a seq.

rest on the other hand always returns a seq, so nothing needs to be evaluated until you actually use the result of rest. In other words, rest is more lazy than next.