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