Since println is supposed to return nil, I expected (nil, nil) to be returned. In reality, the value(\b) that was supposed to be only printed, is also (apparently) returned in the result collection

Ok, let's take this apart some more:

user=> (def f (for [i (range 1 3)] (println \b)))

user=> f

(b

b

nil nil)

Still surprising - I thought I was defining a variable with value being the result of the for macro execution, but it either executed again when f was evaluated, or the result actually contains printed (not captured) values...

Final experiment:

user=> ((vec f) 0)

nil

user=> ((vec f) 1)

nil

user=> ((vec f) 2)

IndexOutOfBoundsException

Now, this reveals that the result actually was correct all along. It is unclear why REPL decided to make the printed values part of the result. Maybe it started with an open parenthesis too early? E.g. it should have printed

b

b

(nil nil)

If so, this is a minor (but confusing for the unitiated) bug. What was more surprising to me is that evaluating f apparently re-evaluated the for. Is this really so? This is not true in the following case: