Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure: *out* vs System/out

Tags:

clojure

I'm trying to translate a small console program I wrote in Java into Clojure, but I'm having a little trouble figuring out the difference between Clojure's standard *out* var and the object at System/out. I was under the impression that they were the same thing, but when during my testing they seem to be different.

In my program I prompt the user to enter a number, and I want the prompt and input text to be on the same line. In Java, I printed the prompt with System.out.print() and then a Scanner read the input.

The following was my first attempt at something similar in Clojure. Though the print function seems like it should fire before the read-line, it immediately blocks on input and prints everything after in a jumbled mess:

(defn inp1 []
    (print "Enter your input: ")
    (let [in (read-line)]
        (println "Your input is: " in)))

The following was my next attempt, using *out*. It suffers from the same problem as the function above:

(defn inp2 []
    (.print *out* "Enter input: ")
    (let [i (read-line)]
        (println "You entered: " i)))

On my third try, I finally got it to work by using System/out directly:

(defn inp3 []
    (let [o System/out]
        (.print o "Enter input: ")
        (let [i (read-line)]
            (println "You entered: " i))))

I'm glad I finally got it to work, but I'm deeply confused as to why the third one works the way I want when the first two don't. Why do the first two block immediately? Can anyone shed some light on this?

like image 719
RGrun Avatar asked Apr 15 '16 01:04

RGrun


1 Answers

Per the docs:

*out* - A java.io.Writer object representing standard output for print operations. Defaults to System/out, wrapped in an OutputStreamWriter

...so, you have a layer of wrapping. Looking at the docs for that layer (emphasis added):

Each invocation of a write() method causes the encoding converter to be invoked on the given character(s). The resulting bytes are accumulated in a buffer before being written to the underlying output stream. The size of this buffer may be specified, but by default it is large enough for most purposes. Note that the characters passed to the write() methods are not buffered.

...emphasis added. Since OutputStreamWriter buffers, you need to call .flush to force content to be written.

like image 130
Charles Duffy Avatar answered Nov 15 '22 09:11

Charles Duffy