varying realization of a lazy-seq of strings?

129 views
Skip to first unread message

TP

unread,
Sep 17, 2017, 6:27:09 PM9/17/17
to clo...@googlegroups.com
Hi,

I am writing to ask if a behavior that I find strange is a bug or
intended? In the latter case I would like to learn why is it so.

In the REPL I see the following, that I think is OK:

user=> (def test-data (lazy-seq [(str ["ZiZi"])]))
#'user/test-data
user=> test-data
("[\"ZiZi\"]")

However, if I call "print" in between the previous 2 lines, test-data
becomes different at the end:

user=> (def test-data (lazy-seq [(str ["ZiZi"])]))
#'user/test-data
user=> (print test-data)
([ZiZi])nil
user=> test-data
("[ZiZi]")

I found that the "binding" of  *print-readably* in the code of "print"
makes the difference. If it is nil (as in print), I get the faulty
value. If it is true, then I get the right (inner-quoted) value.

I learned (from e.g. Stuart Halloway at
http://grokbase.com/t/gg/clojure/149d3t0gwh/schrodingers-cat-in-clojure)
that mixing lazy evaluation and I/O can lead to confusing situations and
that is normal. However here I feel that I get different values of the
same expression depending on which action triggers its realization: if
it is (e.g.) print, then it is realized in a faulty way: "[ZiZi]" is not
correct, since ZiZi should be quoted inside the string by \"-s. (I know
the missing inner quotes are not just a REPL printing issue as I
distilled this question after spending hours to hunt down strange error
messages in a real commercial program.) In other words it seems to me
that having *print-readably* nil, makes the realization of this lazy-seq
failing.

I also see that the problem disappears if I do not use lazy-seq (or
map...) or if I code the string directly (without "str"):

user=> (def test-data (lazy-seq ["[\"ZiZi\"]"]))
#'user/test-data
user=> (print test-data)
(["ZiZi"])nil
user=> test-data
("[\"ZiZi\"]")

and

user=> (def test-data [(str ["ZiZi"])])
#'user/test-data
user=> (print test-data)
[["ZiZi"]]nil
user=> test-data
["[\"ZiZi\"]"]

I verified this behavior both in (pure, i.e. not Lein) REPL of Clojure
1.8 and 1.9.0-alpha20.

Please help me understanding what's going on here.

Thanks,P


Didier

unread,
Sep 17, 2017, 8:59:42 PM9/17/17
to Clojure
Lazy sequences cache their values after the first time they are evaluated. Since print alters the output of str by binding *print-readably* to false, and also forces the sequence to realize itself, the values in your sequence are now cached the the result of str without *print-readably*. In subsequent calls to the sequence, you get the cache results, so even if you change the setting of *print-readably* it doesn't do anything.

Either make sure that when you first access elements of the sequence, the bindings are the way you want str to be configured, or have the bindings set inside the lazy-seq.

Didier

unread,
Sep 17, 2017, 9:06:29 PM9/17/17
to Clojure
Oups, nevermind what I said. str just delegates to .toString and doesn't use *print-readably*. Hum, that is a bit strange then.

Justin Smith

unread,
Sep 17, 2017, 9:09:14 PM9/17/17
to Clojure
my simplified reproduction of the issue:

+user=> (let [mk-str (fn [] (lazy-seq [(str ["ZiZi"])]))
              a (mk-str)
              b (mk-str)]
          (print-str a)
          (pr-str b)
          [a b])
[("[ZiZi]") ("[\"ZiZi\"]")]

isn't *print-readably* the difference between pr-str and print-str?

On Sun, Sep 17, 2017 at 5:59 PM Didier <did...@gmail.com> wrote:
Lazy sequences cache their values after the first time they are evaluated. Since print alters the output of str by binding *print-readably* to false, and also forces the sequence to realize itself, the values in your sequence are now cached the the result of str without *print-readably*. In subsequent calls to the sequence, you get the cache results, so even if you change the setting of *print-readably* it doesn't do anything.

Either make sure that when you first access elements of the sequence, the bindings are the way you want str to be configured, or have the bindings set inside the lazy-seq.

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Michał Marczyk

unread,
Oct 4, 2017, 5:29:52 PM10/4/17
to clojure
That's right. This happens is because collection classes' toString implementations currently delegate to RT.printString, which in turn is affected by the value of *print-readably*.

Filed https://dev.clojure.org/jira/browse/CLJ-2248 with a fix.

Cheers,
Michał


On 18 September 2017 at 03:08, Justin Smith <noise...@gmail.com> wrote:
my simplified reproduction of the issue:

+user=> (let [mk-str (fn [] (lazy-seq [(str ["ZiZi"])]))
              a (mk-str)
              b (mk-str)]
          (print-str a)
          (pr-str b)
          [a b])
[("[ZiZi]") ("[\"ZiZi\"]")]

isn't *print-readably* the difference between pr-str and print-str?
On Sun, Sep 17, 2017 at 5:59 PM Didier <did...@gmail.com> wrote:
Lazy sequences cache their values after the first time they are evaluated. Since print alters the output of str by binding *print-readably* to false, and also forces the sequence to realize itself, the values in your sequence are now cached the the result of str without *print-readably*. In subsequent calls to the sequence, you get the cache results, so even if you change the setting of *print-readably* it doesn't do anything.

Either make sure that when you first access elements of the sequence, the bindings are the way you want str to be configured, or have the bindings set inside the lazy-seq.

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to

For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to

For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages