If you're referring to the distinction between -> and ->>, it's not about direction preference, but rather that functions that conceptually work on a single subject (e.g., conj, assoc) typically take that subject as its first arg, whereas functions that work on a sequence subject (e.g., map, filter) typically take that subject as its last arg. From that consistency emerges the two different threading macros.
(-> (initial) a b c d e)
and
(e (d (c (b (a (initial))))))
I find -> and ->> useful, but the new threading operators kind of silly; they're very easy to implement in terms of -> and ->>, or in terms of higher-order functions, and don't really cover all the use cases one would want---it offends my sense of aesthetics to have them (in their particular implementation) added to the core ns.
and
(e (d (c (b (a (initial)))))) is like "The Californian bay's city".
These variations are different thematic structures to language.
(-> (california) bay-in city-on) ; "The Californian bay's city"
vs. (city-on (bay-in (california))) ; "The city on the bay in California"
The former ("->") starts with what's fed into the pipeline, the latter starts with what you get out of it. In addition, "->" avoids the nesting of expressions regardless of the number of steps, which might be useful in some cases. But both styles have their place.(baz 33 (bar 12 (foo 33 (+ 1 42))))
Is way harder to read than:
(->> (+ 1 42)
(foo 33)
(bar 12)
(baz 33)) (let [fortythree (+ 1 42)
foo33 (foo 33 fortythree)
bar12 (bar 12 foo33)
baz33 (baz 33 bar12)]
baz33)
I understand the logic behind preferring let and a lot of times it really does make things clearer to have everything named and explicit, but especially in prototype code, I find the need to name things to get in the way. I would prefer not naming things over badly named things, for example, and that's usually how I decide between let and thrush (all things being otherwise equal).Clojure can in many senses be written forwards or backwards. By defining this short macro somewhere...
(defmacro topdown-tale [& stmts]
`(do ~@(reverse stmts)))
we can write our top-level control statement at the top and the functions it calls underneath, by bracketing with... (topdown-tale
...
) a(b(c()))
a().b().c()
the latter form requires less mental overhead so why not favour it whenever possible?
The new agent/thread commands sound very interesting:
clojure.core/set-agent-send-executor!, set-agent-send-off-executor!, and send-via
The concurrency primitives have been Clojure's biggest conceptual breakthrough so far, and if they extend that to the automation of thread pools and executors that would amount to building on top of Clojure's greatest strength.
I am less interested in the threading macros (thrush). I dislike the fact that Clojure can, in a sense, be written forwards or backwards. There is a sense of Perl's "there's more than one way to do it" that I dislike.