In Clojure 1.2.0:

=> (count (range 100000000))
100000000
=> (apply count [(range 100000000)])
#<CompilerException java.lang.OutOfMemoryError: GC overhead limit
exceeded (NO_SOURCE_FILE:0)>

I'm not sure why this is happening, but it seems apply is causing the
head of the range to be held somewhere.

This:

=> (apply + (range 100000000))
4999999950000000

indicates that it does not do so if the enormous seq is applied to a
rest argument of the fn; with count, it should just be passing the
(unrealized!) seq as a parameter to count. But apparently it's
internally hanging onto a reference to that seq.

Tracking it down:

=> (. count (applyTo (seq [(range 100000000)])))
#<Boom!>

=> (clojure.lang.AFn/applyToHelper count (seq [(range 100000000)]))
#<All your base are belong to us!>

=> (clojure.lang.RT/boundedLength (seq [(range 100000000)]) 20)
1 ; No kablooey there

=> (let [x (range 100000000)] (clojure.lang.RT/boundedLength (seq [x])
20) (count x))
100000000 ; And again no kaboom; boundedLength isn't causing this

=> (count (clojure.lang.Util/ret1 (.first (seq [(range 100000000)])) nil))
100000000 ; Looks like ret1 isn't the cause either.

=> (.invoke count (clojure.lang.Util/ret1 (.first (seq [(range
100000000)])) nil))
#<You are on the way to destruction!>

; Er, aren't those last two supposed to be *synonymous*?!

; And finally

=> (.invoke count (range 100000000))
#<You have no chance to survive make your time!>

; Now here is something really weird:

=> (let [c #^clojure.lang.AFunction count] (.invoke c (range 100000000)))
100000000

; No kaboom!


As near as I can tell, I've found 2 separate buggy behaviors here.

1: If an interop call uses reflection and passes a lazy seq, the head gets
   held onto somewhere.

2: A non-reflection-using (.invoke count (range 100000000)) does not blow
   up in the REPL, but invoke(count, huge_seq); does when
applyToHelper calls it.

=> (let [c #^clojure.lang.AFunction count]  (.invoke c
(clojure.lang.Util/ret1 (.first (seq [(range 100000000)])) nil)))
100000000

Nope, still not ret1 (which is in fact supposed to prevent this sort of thing).

And the apply function hints the function argument as IFn so it isn't
caused by reflection in apply.

What the devil is going on here???

-- 
Protege: What is this seething mass of parentheses?!
Master: Your father's Lisp REPL. This is the language of a true
hacker. Not as clumsy or random as C++; a language for a more
civilized age.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to