Share your thoughts in the 2024 State of Clojure Survey!

Welcome! Please see the About page for a little more info on how this works.

0 votes
in Printing by

Using \~I and \~_ etc fails in many situations, the most trivial one being:

Clojure 1.6.0 and 1.5.1:

user=> (clojure.pprint/cl-format true "~I") ClassCastException java.io.PrintWriter cannot be cast to java.util.concurrent.Future clojure.core/deref-future (core.clj:2180) user=> (clojure.pprint/cl-format nil "~I") ClassCastException java.io.StringWriter cannot be cast to java.util.concurrent.Future clojure.core/deref-future (core.clj:2180) user=> (clojure.pprint/cl-format nil "~_") ClassCastException java.io.StringWriter cannot be cast to java.util.concurrent.Future clojure.core/deref-future (core.clj:2180)

Clojure 1.4.0

user=> (clojure.pprint/cl-format true "~I") ClassCastException java.io.OutputStreamWriter cannot be cast to clojure.lang.IDeref clojure.core/deref (core.clj:2080) user=> (clojure.pprint/cl-format nil "~I") ClassCastException java.io.StringWriter cannot be cast to clojure.lang.IDeref clojure.core/deref (core.clj:2080) user=> (clojure.pprint/cl-format nil "~_") ClassCastException java.io.StringWriter cannot be cast to clojure.lang.IDeref clojure.core/deref (core.clj:2080)

These work in other implementations, i.e. clisp, creating empty output in these trivial cases:

> (format t "~I") NIL > (format nil "~I") "" > (format nil "~_") ""

4 Answers

0 votes
by

Comment made by: jafingerhut

The tilde-underscore sequence is for "conditional newline", according to the CLHS here: http://www.lispworks.com/documentation/lw51/CLHS/Body/22_cea.htm

Tilde-capital-letter-I is for indent: http://www.lispworks.com/documentation/lw51/CLHS/Body/22_cec.htm

0 votes
by

Comment made by: neapel

Ah, didn't think to try that. It fails without cl-format as well:

user=> (clojure.pprint/pprint-newline :linear) ClassCastException java.io.PrintWriter cannot be cast to java.util.concurrent.Future clojure.core/deref-future (core.clj:2180) user=> (clojure.pprint/pprint-indent :block 0) ClassCastException java.io.PrintWriter cannot be cast to java.util.concurrent.Future clojure.core/deref-future (core.clj:2180)

Manually creating a pretty writer does work though:

user=> (binding [*out* (clojure.pprint/get-pretty-writer *out*)] (clojure.pprint/pprint-newline :linear)) nil

In the get-pretty-writer doc it says:
{quote}
Generally, it is unnecessary to call this function, since pprint,
write, and cl-format all call it if they need to.
{quote}
Which appears to not be true for cl-format, and it would be nice if it would be applied automatically for all functions that need a pretty writer.

0 votes
by

Comment made by: neapel

More bad news!
Manually creating a pretty-writer doesn't do the trick either, because it is not being properly flushed:

user=> (binding [*out* (get-pretty-writer *out*)] (cl-format true "hello ~_world~%")) hello world nil user=> (binding [*out* (get-pretty-writer *out*)] (cl-format true "hello ~_world")) hellonil user=> (binding [*out* (get-pretty-writer *out*)] (cl-format true "hello ~_world") (.ppflush *out*)) hello worldnil

The ~% inserts an unconditional newline like {{\n}}, which also works as expected.

Insert \~\_ before and it only prints up to that one. But I've also managed to get it to abort at other \~\_ s, maybe because other commands flushed it.

Manually flushing it, like the inexplicably private {{with-pretty-writer}} macro does works though.
I don't understand why {{get-pretty-writer}} is exposed but not the macro that is needed to use it properly. Also all functions using pretty-writer facilities should use with-pretty-writer, that's what it appears to be specifically designed for. Then there's no need to expose it (or get-pretty-writer).

0 votes
by
Reference: https://clojure.atlassian.net/browse/CLJ-1462 (reported by alex+import)
...