from a practical perspective the fact that for
returns a lazy sequence means that it won't work in core.async where doseq does because it runs entirely within the same function.
user> (require '[clojure.core.async :refer [chan go <! <!! >!]])
using doseq:
user> (let [stuff (chan)]
(go (while true
(println (<! stuff))))
(go (doseq [a (range 4)]
(>! stuff a))))
#object[clojure.core.async.impl.channels.ManyToManyChannel 0x523a18bc "clojure.core.async.impl.channels.ManyToManyChannel@523a18bc"]
user> 0
1
2
3
using for and dorun:
user> (let [stuff (chan)]
(go (while true
(println (<! stuff))))
(go (dorun (for [a (range 4)]
(>! stuff a)))))
CompilerException java.lang.IllegalArgumentException: No method in multimethod '-item-to-ssa' for dispatch value: :fn, compiling:(form-init5662188991458325584.clj:4:9)
fails because it tries to cross a function call within a go block and hence escapes from the go macro's scope.