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 [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---