For context, started on Slack at https://clojurians.slack.com/archives/C03S1L9DN/p1650480331191719
This code works just fine on CLJ but fails with StackOverflowError
on CLJS:
(def primes (remove
(fn [x]
(some #(zero? (mod x %)) primes))
(iterate inc 2)))
The vital difference between CLJ and CLJS in this case is that in the former, lazy-seq
ends up wrapping its whole body in a function with ^:once
.
The reasoning why it works that way is because in the code above, the inner primes
is a closed over value, it becomes a local. When the body fn of a lazy-seq
(the one with ^:once
) is called the second time, its locals are nil
, so that inner primes
is also nil
. And iteration stops.
In CLJS, there's no :once
and no locals clearing, so the inner primes
is never nil
, and the execution keeps on going into that fn
without even calling that zero?
.
Even if the reasoning doesn't sound plausible, the hypothesis that it's indeed :once
that's to blame for the difference can be easily confirmed by implementing lazy-seq
in CLJ without :once
and noticing that it leads to StackOverflowError
.
It's unclear to me what to do in this case, but perhaps at least a note on the https://clojurescript.org/about/differences page should be made about it.