A conversation on IRC tonight[1] got me thinking...  Although most
collections can be safely printed, such as at the REPL, this is not
true of all collections.  Probably the best-known exception in Clojure
are infinite lazy sequences, where printing can cause an infinite
loop:

(prn (iterate inc 0))  ; careful, you may not want to do this.

This particular issue is addressed by the *print-level* var:

user=> (binding [*print-length* 17] (prn (iterate inc 0)))
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ...)
nil

Similarly, infinitely nested seqs can cause problems:

user=> (prn ((fn x [] (lazy-cons (x) nil))))
java.lang.StackOverflowError (NO_SOURCE_FILE:0)

Again, there's a var for this:

user=> (binding [*print-level* 5] (prn ((fn x [] (lazy-cons (x) nil)))))
(((((#)))))

But now that atoms, agents, and refs print their contained value (as
of svn 1254), a new kind of infinite nesting error is possible:

(binding [*print-level* 4]
  (let [a (atom nil)]
    (prn (reset! a a))))

This currently causes a StackOverflowError, but a patch and workaround
are available[2]:

#<a...@1a9d1b: #<a...@1a9d1b: #<a...@1a9d1b: #<a...@1a9d1b: #>>>>

But this is not the only possible problem with print deref'ing.
Another is that it may block on the new future objects:

user=> (let [f (future (Thread/sleep 3000) :done)] (prn f))
...three second delay...
#<object$future$ide...@9c2715: :done>

I'm not sure how much of a problem this is.  One option would be
print method for future objects that doesn't deref when the future
object is not yet done:

(.addMethod print-method (class (future))
            (fn [o w]
              (.write w (format "#<fut...@%x%s>"
                                (System/identityHashCode o)
                                (if (.isDone o)
                                  (str ": " @o)
                                  " not done")))))

user=> (def f (future (Thread/sleep 3000) 777))
#'user/f
user=> f
#<fut...@1347124 not done>

...wait few seconds, then...
user=> f
#<fut...@1347124: 777>

I'm not sure if this is worth doing or not.  It's certainly not the
only kind of trouble you can get into, printing objects.  Any mutable
Java collection can cause a problem:

(let [m1 (java.util.HashMap.)
      m2 (java.util.HashMap. {:m1 m1})]
  (.put m1 :m m2)
  (prn m1))
java.lang.StackOverflowError (NO_SOURCE_FILE:0)

That's actually caused by HashMap's .toString method, so it's entirely
outside Clojure's control.

--Chouser

[1] http://clojure-log.n01se.net/date/2009-02-09.html#17:53d
[2] http://code.google.com/p/clojure/issues/detail?id=71

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

Reply via email to