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

0 votes
in Sequences by

The following code is somewhat surprising to me:

user> (def bla (filter #(throw (Exception. %)) ["lol" "foo"]))
;; => #'user/bla
user> (prn bla)
Execution error at sun.reflect.NativeConstructorAccessorImpl/newInstance0 (NativeConstructorAccessorImpl.java:-2).
user> (prn bla)
;; => nil

That the def doesn't throw is expected, that the first prn throws is also expected.
What's unexpected is that the second prn returns the empty list.

Digging a bit more, it turns out that removing the :once meta on lazy-seq, I get expected behaviour, ie the second prn throws too.

1 Answer

+2 votes

Variants of this have been discussed in the past. The general advice is: we don't make any guarantees about what happens if lazy seqs throw on realization. If you're doing side effect-y things in your lazy seq, consider using run!, loop/recur, etc.

See https://clojure.atlassian.net/browse/CLJ-2069 for a similar ticket.