As discovered by cmvkk in IRC:

user=> (count (reduce #(cons %2 %) [0] (range 4601)))
java.lang.StackOverflowError (NO_SOURCE_FILE:0)

This is because Cons.count() is recursive via RT.count().  Presumably
it's to allow efficient counting of heterogeneous seqs, like:

 user=> (def big-vec (into [] (range 10000000))) ; this is slow
#'user/big-vec
user=> (count (cons :a big-vec)) ; but this is fast
10000001

I've attached a patch that keeps this latter efficiency, but won't
blow the stack for pure chains of Cons's.  However, it has
Cons.count() still defer to RT.count() for non-Cons rests.  Since I
couldn't find any other class that uses this kind of recursion for
count(), it may be impossible to build a seq that would still cause
Cons.count() to overflow the stack, but I'm not completely certain.

An alternative, of course, would be to do a simple loop as
ASeq.count() does, at the cost of the efficient vector counting
demonstrated above.

If you have comments or questions, don't hesitate or I'll move this to
the issues page!

--Chouser

--~--~---------~--~----~------------~-------~--~----~
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
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
-~----------~----~----~----~------~----~------~--~---

commit 5573feb9cdfc16533e2b27fa27013cc0b68822ba
Author: Chouser <chou...@n01se.net>
Date:   Tue Jan 6 23:08:26 2009 -0500

    Avoid stack overflow on Cons.count()

diff --git a/src/jvm/clojure/lang/Cons.java b/src/jvm/clojure/lang/Cons.java
index c9e65eb..c7ef54f 100644
--- a/src/jvm/clojure/lang/Cons.java
+++ b/src/jvm/clojure/lang/Cons.java
@@ -38,7 +38,11 @@ public ISeq rest(){
 }
 
 public int count(){
-	return 1 + RT.count(_rest);
+	int i = 1;
+	for(ISeq s = rest(); s != null; s = s.rest(), i++)
+		if( ! (s instanceof Cons) )
+			return i + RT.count(s);
+	return i;
 }
 
 public ISeq seq(){

Reply via email to