Clojure: apply println to multiple strings scrambles output

92 Views Asked by At

In Clojure 1.11, I'm evaluating this term:

(apply println "foo\n" "bar\n" "baz\n")

I expect the following output:

foo
bar
baz

However, I'm getting this:

foo
 bar
 b a z

The first line is as I need it. The second line contains a leading space. The third line has a superfluous space before each letter.

Why is behaving apply/println like that, and how can I get the desired output?

3

There are 3 best solutions below

1
Eugene Pakhomov On BEST ANSWER

Leading spaces come from the fact that println adds spaces when printing its arguments. E.g. try (println 1 2 3) - you'll get 1 2 3 in the output.

The last line comes out as it does because you're using apply. apply treats the last argument as a collection as passes its items as separate arguments to the target function. So in this case you most likely don't need apply at all.

To achieve what you want, you should use something like (run! print ["foo\n" "bar\n" "baz\n"]). Or use println and don't add \n yourself since println does that for you.

0
Harold On

Another thought:

user> (apply println "foo\n" "bar\n" "baz\n")
foo
 bar
 b a z 

nil
user> (print (str "foo\n" "bar\n" "baz\n"))
foo
bar
baz
nil
1
Alan Thompson On

Since you are adding your own linefeeds,

(print (str "foo\n" "bar\n" "baz\n")) 

with result

foo
bar
baz

is by far the simplest & clearest option. The purpose of apply is if you have several items contained in a sequence:

(apply print [ "foo\n" "bar\n" "baz\n" ] ) 

however, print till adds in a \space in between each token! Doh!

foo
 bar
 baz

So if you do have the 3 args in a vector, you need one of these:

  (print (apply str            ["foo\n" "bar\n" "baz\n"]))
  (print (clojure.string/join  ["foo\n" "bar\n" "baz\n"]))

both of which produce the desired result.