CLJ loop bindings hold on to head of lazy sequence

37 views
Skip to first unread message

Luke VanderHart

unread,
Jun 1, 2012, 2:45:38 PM6/1/12
to cloju...@googlegroups.com
Consider the following Clojure code:

(let [s (range 10000000)]
  (reduce + s))

This behaves nicely and returns the value 49999995000000

Now consider this code:

(loop [s (range 10000000)]
  (reduce + s))

In this case, the loop binding holds on to the head of the sequence,
resulting in an OutOfMemoryError.

Of course, using loop without recur is pointless: this is only a
degenerate case to illustrate the problem. The issue actually does
show up in real code, where a loop might have a conditional to either
recur or bail to an alternative handler. This is actually happening
right now in the clojure.lang.Object impelementation of
clojure.core.protocols/internal-reduce.

Should I file this as a bug, or is there a good reason for this that I
haven't thought of?

Thanks,
-Luke

Tassilo Horn

unread,
Jun 1, 2012, 3:01:12 PM6/1/12
to cloju...@googlegroups.com
Luke VanderHart <luke.va...@gmail.com> writes:

> Consider the following Clojure code:
>
> (let [s (range 10000000)]
> (reduce + s))
>
> This behaves nicely and returns the value 49999995000000
>
> Now consider this code:
>
> (loop [s (range 10000000)]
> (reduce + s))
>
> In this case, the loop binding holds on to the head of the sequence,
> resulting in an OutOfMemoryError.

Running 1.4.0, both work fine for me. What version are you using?

Bye,
Tassilo

Tassilo Horn

unread,
Jun 1, 2012, 3:05:13 PM6/1/12
to cloju...@googlegroups.com
Tassilo Horn <tas...@member.fsf.org> writes:

>> Consider the following Clojure code:
>>
>> (let [s (range 10000000)]
>> (reduce + s))
>>
>> This behaves nicely and returns the value 49999995000000
>>
>> Now consider this code:
>>
>> (loop [s (range 10000000)]
>> (reduce + s))
>>
>> In this case, the loop binding holds on to the head of the sequence,
>> resulting in an OutOfMemoryError.
>
> Running 1.4.0, both work fine for me. What version are you using?

Oh, too fast. I can reproduce the issue by using a hundred times longer
range...

Bye,
Tassilo

Luke VanderHart

unread,
Jun 1, 2012, 3:28:24 PM6/1/12
to cloju...@googlegroups.com
Yes, the size of the range needed to cause the error varies depending how much memory you're running with.

The error is present on the master branch as of this morning.

Tassilo Horn

unread,
Jun 1, 2012, 4:00:32 PM6/1/12
to cloju...@googlegroups.com
Luke VanderHart <luke.va...@gmail.com> writes:

Hi Luke,

> Yes, the size of the range needed to cause the error varies depending
> how much memory you're running with.
>
> The error is present on the master branch as of this morning.

LetExpr in Compiler.java is the implementation of both let* and loop*.
Not that I'd understand it right now, but in the loop* case it pushes
and pops some thread bindings and the LOOP_LOCALS dynamic var looks
suspicious...

Bye,
Tassilo
Reply all
Reply to author
Forward
0 new messages