While exploring various ways of computing factorials in Clojure, I came up with the following (non-idiomatic) function:
(defn factorial-using-do-dotimes [x]
(do
(def a 1)
(dotimes [i x]
(def a (* a (inc i)))))
a)
REPL:
user=> (factorial-using-do-dotimes 5)
120
What are the concrete disadvantages of this (aside from “non-idiomatic”)? Performance? Correctness (that is, possible defects)?
Using def inside a function body is not idiomatic, sort-of-but-not-explicitly undefined behavior, and considering the way vars are implemented, using
(dotimes .. (def ..))is quite possibly slower than using(loop ... (recur ...)), especially when you’re using basic types, like numbers, and type-hints.The main reason not to do this kind of “dynamic” modification of vars, is that it complicates your code for no good reason. Some much more idiomatic combination of loop/recur and transients should under normal circumstances get you as good a performance as you can get out of clojure. And it will still be thread-safe, predictable and readable.
Edit: as a concrete defect: your example code does not work correctly when called from multiple threads concurrently.