Welcome! Please see the About page for a little more info on how this works.

+1 vote
ago in Collections by

The doc string for nth reads:

clojure.core/nth
([coll index] [coll index not-found])
Returns the
value at the index. get returns nil if index out of bounds, nth
throws an exception unless not-found is supplied. nth also works
for strings, Java arrays, regex Matchers and Lists, and, in O(n)
time, for sequences.

The behavior agrees when the coll is [] or '() or other empty collections. However:

user=> (nth [] 10) Execution error (IndexOutOfBoundsException) at user/eval280 (REPL:1). null user=> (nth nil 10) nil

Trying to get the 10th item of [] throws but trying to get the 10th item of nil returns nil.

1 Answer

0 votes
ago by

This is the expected behvaior (older ticket where this was considered is at https://clojure.atlassian.net/browse/CLJ-2029). nth, like get or contains? has polymorphic behavior on nil, and that is as intended. The docstring could probably be clarified.

ago by
OK. I think the docstring should definitely be clarified.
ago by
Having said that:

```
user=> (nth (rest [1]) 10)
Execution error (IndexOutOfBoundsException) at user/eval286 (REPL:1).
null
user=> (nth (next [1]) 10)
nil
```

That there is a huge difference in the behavior of `nth` after taking the `rest` of a sequence and the `next` of a sequence is odd.
ago by
yes. there is a huge difference between nothing and something
ago by
Can you elaborate on the thinking here? CLJ-2029 basically just states the same thing (the behavior is "by design"). I'm struggling to understand that design.

I'd also note that CLJ-2029 also suggests changing the doc string, but that comment was made 10 years ago and it's still not changed. As we find these disconnects between doc strings and actual behavior, what does it take to get doc strings changed if we decide the behavior is "by design?" Doc string changes are not breaking, right? Is there anything preventing the doc string from being changed in the next release?
ago by
In general, there is a philosophy in Clojure core functions of aggressive polymorphism - making different types of collection (or nil) do something useful. For collection retrieval functions in particular, returning nil (rather than throwing) allows you to chain retrievals through deep data structures and bottom out at nil via the various "some" functions (like `some->`) OR to do nil-punning conditional logic on nil.

I've logged as https://clojure.atlassian.net/browse/CLJ-2971
...