For collections and sequences, when calling str on them, Clojure will return an EDN-like representation of them as string more similar to the result of pr-str:
(str (vector 1 2 3))
"[1 2 3]"
(str '(1 2 3))
"(1 2 3)"
(str (seq [1 2 3]))
"(1 2 3)"
(str {:a 1 :b 2})
"{:a 1, :b 2}"
(str #{1 2})
"#{1 2}"
But when used on lazy-seq, str will print the type of lazy-seq followed by the hash of its realized values:
(str (lazy-seq [1 2 3]))
"clojure.lang.LazySeq@7861"
Not only could this be argued to be a rather useless behavior for most use case (as most people probably would rather it stringified the same as seq does. It also force realizes the lazy-seq:
(let [ls (map inc [1 2 3])]
(realized? ls))
;;=> false
(let [ls (map inc [1 2 3])]
(str ls)
(realized? ls))
;;=> true
Similarly, when used on eductions, str will print the type of eduction this time followed by the memory location:
(str (eduction identity [1 2 3]))
"clojure.core.Eduction@2a85e4f4"
Unlike for lazy-seq, it will not "realize" the eduction:
(str (eduction (fn[e] (println e) (identity e)) [1 2 3]))
"clojure.core.Eduction@26ae9861"
(str (map (fn[e] (println e) (identity e)) [1 2 3]))
1
2
3
"clojure.lang.LazySeq@7861"
It seems like the current behavior for lazy-seq and eduction is either inconsistent or wrong.
Ideally it would behave either where:
str would cause neither lazy-seq nor eduction to realize themselves, but would still stringify as only their type. The idea here would be that str does not realize "pending" computation, thus it would be safe to use on infinite lazy-seqs or repeatedly on eductions.
- Or
str would always realize the "pending computation", and thus lazy-seq and eduction would both stringify the same as other collections and sequences do, more similar to calling pr-str on them.
P.S.: It might be relevant when making a decision to consider that ClojureScript currently behaves differently in that it does option 2 for lazy-seq and I'm not sure what it does for eduction:
cljs.user=> (str (lazy-seq [1 2 3]))
"(1 2 3)"
cljs.user=> (str (eduction identity [1 2 3]))
"[object Object]"
P.S.2: It also appears the behavior when a lazy-seq or an eduction is nested inside another collection or sequence differs in that in those scenarios, they will get stringified in an EDN-like fashion:
(str [1 (map identity [2 3]) 4])
"[1 (2 3) 4]"
(str (seq [1 (map identity [2 3]) 4]))
"(1 (2 3) 4)"
(str [1 (eduction identity [2 3]) 4])
"[1 (2 3) 4]"
(str (seq [1 (eduction identity [2 3]) 4]))
"(1 (2 3) 4)"
This seems to be the case in ClojureScript as well.