Clojure output binding reset in for loop - clojure

I'm new to Clojure, and am trying to redirect output to a file by rebinding *out*. In a simple case, it works nicely:
(binding [*out* (new java.io.FileWriter "test.txt")]
(println "Hi"))
This does what I expect, printing "Hi" to the file test.txt. However, if I introduce a for loop, things go awry:
(binding [*out* (new java.io.FileWriter "test.txt")]
(for [x [1 2]]
(println "Hi" x)))
This time, all the output goes to stdout, and the file is empty. What's going on here?
I'm using Leiningen, if that makes any difference:
Leiningen 2.0.0 on Java 1.7.0_13 Java HotSpot(TM) 64-Bit Server VM

you have been bitten by the lazy bug.
put a doall or dorun around the for and within the binding
(binding [*out* (new java.io.FileWriter "test.txt")]
(doall (for [x [1 2]]
(println "Hi" x))))
In your example the printing is happening then the result is printed by the repl after it is returned from the binding. So at the time of printing the binding is no longer in place.
Nothing is printed because result is a lazy sequence that will later be evaluated when used
user> (def result (binding [*out* (new java.io.FileWriter "test.txt")]
(for [x [1 2]]
(println "Hi" x))))
#'user/result
When the repl prints the resuls the printlns are evaluated:
user> result
(Hi 1
Hi 2
nil nil)
If we force the evaluation of the lazy sequence returned by for within the binding
nothing is printed to the repl,
user> (def result (binding [*out* (new java.io.FileWriter "test.txt")]
(doall (for [x [1 2]]
(println "Hi" x)))))
#'user/result
user> result
(nil nil)
and instead the output ends up in the file:
arthur#a:~/hello$ cat test.txt
Hi 1
Hi 2

Related

Printing inside a for loop

I was practicing one Clojure tutorial and had to ensure that a for loop was executed so I put a println command there, but it did not display messages.
So now I have got the question...
This code prints Tom's name:
(ns tutorial.core)
(defn -main []
(println 'Jane)
(for [a ['Tom]]
(println a))
;; 'Kate
)
tutorial.core> (-main)
Jane
Tom
(nil)
tutorial.core>
but this not:
(ns tutorial.core)
(defn -main []
(println 'Jane)
(for [a ['Tom]]
(println a))
'Kate
)
tutorial.core> (-main)
Jane
Kate
tutorial.core>
Why? In which cases can we expect that println will not print texts?
for is not a loop, it is a sequence comprehension which returns a lazy sequence. Your for expression will therefore only execute its side-effects (calls to println) when the returned sequence is evaluated. The REPL evaluates the values returned from your calls to -main so it can print them.
Your first example returns a lazy sequence which is evaluted by the REPL causing the (println 'Tom) call to be evaluated. Since println returns nil, the resulting sequence contains a single nil value - this is the (nil) you see in the output.
Your second example creates the same sequence but does not evaluate it, instead 'Kate is returned from the function and the REPL prints that.
If you want an imperative for loop you should use doseq:
(defn -main []
(println 'Jane)
(doseq [a ['Tom]]
(println a))
'Kate)
As Lee says, if you only want side effects like printing, a doseq is the best solution as it never returns a value other than nil.
If you do want to use a for loop, you can remove the laziness by wrapping it inside a (vec ...) expression, which will force the for loop to run immediately. Thus we get:
(println :start)
(vec
(for [a [1 2 3]]
(println a)))
(println :end)
with result:
:start
1
2
3
:end
Without the vec, we get the behavior you saw:
(println :start)
(for [a [1 2 3]]
(println a))
(println :end)
with result:
:start
:end
I almost never want a lazy result, as the uncertainty over when a computation occurs can make debugging difficult. I use the above construct so often that I wrote a small macro forv that always returns a vector result, similar to the mapv function.

repeatedly vs. binding

(def ^:dynamic *d* 1)
(binding [*d* 2]
(println *d*)
(repeatedly 1 #(println *d*)))
Output:
2
1
Why? Why does the function inside the repeatedly see the value of the dynamic var from outside the binding?
By the way, I checked (.getId (java.lang.Thread/currentThread)) inside and outside the anonymous function: it's the same.
The lazy sequence created by repeatedly is returned from the form, and then realized only when printed via the REPL, after the binding has been "unwound," and it is at this point that the anonymous function is being called. To see that this is the case, try these two variations:
(binding [*d* 2]
(println *d*)
(let [x (repeatedly 1 #(println *d*))]
(println (realized? x))
x))
and
(binding [*d* 2]
(println *d*)
(doall (repeatedly 1 #(println *d*))))
The second variation forces the sequence to be fully realized while still within the scope of the binding.
Note that another way to force the issue is to "capture" the binding by using bound-fn:
(binding [*d* 2]
(println *d*)
(repeatedly 1 (bound-fn [] (println *d*))))

Clojure: how to know if a function (test-vars) printed something to *out*?

I am looking for a way to determine if a function printed (using println or anything similar).
What I am trying to determine is if test-vars printed something or not.
The issue with this function is that it doesn't return anything, but only print things when errors got issues, but I want to know if it succeeded or not and the only way I see to know it is to check if it printed something or not.
Even better would be a way to "intercept" what is going to out and to put it in a variable.
After the comments from #lee and #leetwinski I tried the following:
(deftest test-1
(testing
(is (= 1 2))))
Then I tried to run that test using:
(let [printed (with-out-str (test-vars [#'test-1]))]
(print (str "Printed size: " (count printed))))
But here is what I got:
FAIL in (test-1) (form-init505699766276988020.clj:103)
expected: (= 1 2)
actual: (not (= 1 2))
Printed size: 0
nil
So, what test-vars outputs has been outputted anyway. Then printed was empty.
in addition to #Lee's answer: in general you could just rebind *out* to any other writer you want:
temporary binding:
user> (binding [*out* (java.io.StringWriter.)]
(println 101)
(str *out*))
"101\n"
is just an analogue to with-out-str
thread-local binding:
user> (set! *out* (java.io.StringWriter.))
#object[java.io.StringWriter 0x575e6773 ""]
user> (println 123)
nil
user> (str *out*)
"123\n"
here we rebind the *out*, for the current thread (and for all the threads, spawned from it, AFAIK).
You can use with-out-str which intercepts printed values and collects them into a string:
(let [printed (with-out-str (test-vars))]
...)

clojure -- name conflicts in a defined record?

I have a misbehaving piece of code; when I name a record MethodInfo, it no longer overrides the .toString method correctly.
(defrecord MethodInfo [^clojure.lang.ISeq x ^clojure.lang.ISeq y]
java.lang.Object
(toString [x]
(str (:x x))))
Running a simple test shows how this fails,
=> (.toString (new MethodInfo [1 2] [3]))
"sketch.compiler.main.sklojure1.MethodInfo#10e0d118"
whereas renaming the record to A shows the code behaving correctly,
=> (.toString (new A [1 2] [3]))
"[1 2]"
what am I doing wrong??
Your record works fine for me. I would recommend restarting the REPL as there might be some old code hanging around. Note also that you have direct access to fields in the record, so you can write
(defrecord MethodInfo [x y]
Object
(toString [_] (str x)))
instead of
(defrecord MethodInfo [x y]
Object
(toString [this] (str (:x this))))

how to unit test for laziness

I have a function that is supposed to take a lazy seq and return an unrealized lazy seq. Now I want to write a unit test (in test-is btw) to make sure that the result is an unrealized lazy sequence.
user=> (instance? clojure.lang.LazySeq (map + [1 2 3 4] [1 2 3 4]))
true
If you have a lot of things to test, maybe this would simplify it:
(defmacro is-lazy? [x] `(is (instance? clojure.lang.LazySeq ~x)))
user=> (is-lazy? 1)
FAIL in clojure.lang.PersistentList$EmptyList#1 (NO_SOURCE_FILE:7)
expected: (clojure.core/instance? clojure.lang.LazySeq 1)
actual: (not (clojure.core/instance? clojure.lang.LazySeq 1))
false
user=> (is-lazy? (map + [1 2 3 4] [1 2 3 4]))
true
As of Clojure 1.3 there is also the realized? function: "Returns true if a value has been produced for a promise, delay, future or lazy sequence."
Use a function with a side effect (say, writing to a ref) as the sequence generator function in your test case. If the side effect never happens, it means the sequence remains unrealized... as soon as the sequence is realized, the function will be called.
First, set it up like this:
(def effect-count (ref 0))
(defn test-fn [x]
(do
(dosync (alter effect-count inc))
x))
Then, run your function. I'll just use map, here:
(def result (map test-fn (range 1 10)))
Test if test-fn ever ran:
(if (= 0 #effect-count)
(println "Test passed!")
(println "Test failed!"))
Since we know map is lazy, it should always work at this point. Now, force evaluation of the sequence:
(dorun result)
And check the value of effect-count again. This time, we DO expect the side effect to have triggered. And, it is so...
user=>#effect-count
9