I was looking at testing lazy seqs for #clojure-test-suite. I see that the doc string for range says
Returns a lazy seq of nums from start (inclusive) to end (exclusive), by step, where start defaults to 0, step to 1, and end to infinity. When step is equal to 0, returns an infinite sequence of start. When start is equal to end, returns empty list.
But range actually returns a clojure.lang.LongRange or clojure.lang.Range not a clojure.lang.LazySeq. This pops up in that (realized? (range 10)) throws since range doesn’t return a lazy seq. The doc string for range seems stale (I’m guessing it did return a lazy seq at some point, but probably got optimized). If that’s true, what’s the correct way to determine if a range is realized? And yes, I know that I can for a lazy seq using (realized? (lazy-seq (range 10)) and that works. But that’s not what I’m after.those things are lazy seqs (but not LazySeqs)
Exactly
so doc string is correct
I debated the realized? thing a lot during impl of LongRange and Range
I would say that the doc string is misleading.
well, they are lazy, and they are seqs. what should it say that would be better?
imo, realized? itself is broken in that it should never throw (I have a jira for this). it's current behavior is rarely ever useful and often a footgun
If it's a lazy seq then realized? should work on it, right?
see https://clojure.atlassian.net/browse/CLJ-1752 (realized?) and https://clojure.atlassian.net/browse/CLJ-1751 (IPending on Range)
How do I detect whether a LongRange is realized?
it is effectively always realized, it is just math
or never realized, depending on how think about it :)
Right. It's iterable and the math just backs that
Okay, lemme do some Jira reading and get a more informed opinion.
I have spent a truly indefensible amount of time working on the (re-)implementation of range in my life
LOL
same…
Okay, sorry for grinding on a sore point
oh no worries :)
OK, having looked at this for a few minutes and collected my thoughts, here’s what I think. It seems like the solution in CLJ-1752 is correct. Thus, a LongRange is always realized. @alexmiller, you said before that there’s a question of what realized? means. What did it mean before Clojure 1.7 for LazySeqs? I assume it would only be a question as to whether the first element in the seq was realized. And for LongRange, it always has that next value ready (because math). I assume that realized? could never have meant “Is the whole sequence realized?” because that would be potentially expensive. So, I would vote for CLJ-1752 so at least realized? doesn’t throw when given a LongRange.
Yes, I think it must be about the first element, but the cases where asking even that question is useful are so rare and/or delicate that I struggle to find any case where someone could or should use it
I agree with that. I’ve never used realized? except for futures/promises/etc.
If you care about the answer, you should probably not be using lazy seqs
Right
Makes sense for future/ promise
Totally
So, to be clear, all my answers here are coming from the point of view of what is self-consistent for Clojure given the history and desire to preserve behavior. I’m specifically NOT saying what I would want or use.
but given that it's both documented behavior and partially implemented, seems worthwhile to make it consistent
Right
I’m testing it in #clojure-test-suite, so I want to know what is canonical behavior so that other dialects can conform to that.
the number of times alex has had to explain the pitfalls of realized? is enough to make your head spin
LOL
Perhaps just worth pointing out that realized? throws on "most" argument types. Maybe realized?'s docstring should be updated to mention IPending?
In Clojure 1.6, (realized? (range 10)) was false. In Clojure 1.7, it throws. (realized? []), for example, throws in Clojure 1.6 (and 1.7 onward), so it was already a pretty niche function 🙂
Yea, it seemed like Clojure “evolved” there and realized? was one of those functions that only came along for half the ride.
Again, the right solution is imo to “fix” realized?
Not worry about range or IPending (which is an implementation detail)
Yes agreed.
Test suites should be careful not to pour concrete on observed behaviors
That's precisely why I started this conversation. I want to clarify what the contract is or should be so that I'm not flagging behavior that is incidental and historical