clojure-dev 2026-04-21

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.

Alex Miller (Clojure team) 2026-04-21T21:23:36.154449Z

those things are lazy seqs (but not LazySeqs)

😵‍💫 1
Alex Miller (Clojure team) 2026-04-21T21:24:28.137769Z

so doc string is correct

👎 1
Alex Miller (Clojure team) 2026-04-21T21:24:42.104179Z

I debated the realized? thing a lot during impl of LongRange and Range

I would say that the doc string is misleading.

Alex Miller (Clojure team) 2026-04-21T21:29:22.857349Z

well, they are lazy, and they are seqs. what should it say that would be better?

Alex Miller (Clojure team) 2026-04-21T21:30:31.499769Z

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

👍 1

If it's a lazy seq then realized? should work on it, right?

How do I detect whether a LongRange is realized?

Alex Miller (Clojure team) 2026-04-21T21:33:01.208319Z

it is effectively always realized, it is just math

Alex Miller (Clojure team) 2026-04-21T21:33:21.177559Z

or never realized, depending on how think about it :)

😂 1

Right. It's iterable and the math just backs that

Okay, lemme do some Jira reading and get a more informed opinion.

Alex Miller (Clojure team) 2026-04-21T21:35:01.546039Z

I have spent a truly indefensible amount of time working on the (re-)implementation of range in my life

😄 1

Okay, sorry for grinding on a sore point

Alex Miller (Clojure team) 2026-04-21T21:36:47.887019Z

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.

👍 1
Alex Miller (Clojure team) 2026-04-21T22:26:22.820699Z

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.

Alex Miller (Clojure team) 2026-04-21T22:27:05.404019Z

If you care about the answer, you should probably not be using lazy seqs

Alex Miller (Clojure team) 2026-04-21T22:27:25.781929Z

Makes sense for future/ promise

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.

👍 1

but given that it's both documented behavior and partially implemented, seems worthwhile to make it consistent

👍 1

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

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.

👍 1
Alex Miller (Clojure team) 2026-04-21T23:02:37.569759Z

Again, the right solution is imo to “fix” realized?

Alex Miller (Clojure team) 2026-04-21T23:03:10.285349Z

Not worry about range or IPending (which is an implementation detail)

👍 2

Test suites should be careful not to pour concrete on observed behaviors

👍 1
➕ 1
👆 1

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

👍 2
👍🏼 1