Every time you make a global var that you plan to re-bind, you're adding an extra implicit argument to every function that accesses that variable. Unlike proper (explicit) arguments, this hidden argument doesn't show up in the functions's signature and there may be little indication that the function is using it. Your code become less "functional"; calling the same function with the same arguments may result in different return values based on the current state of these global dynamic vars.
The benefit of global vars is that you can easily specify a default value, and it lets you be lazy by not having to pass that var around to every function that uses it.
The downside is that your code is harder to read, test, use and debug. And your code becomes potentially more error-prone; it's easy to forget to bind or re-bind the var before you call the function that uses it, but it's not so easy to forget to pass in a session
parameter when it's right in the arglist.
So you end up with mystery bugs, and weird implicit dependencies between functions. Consider this scenario:
user> (defn foo [] (when-not (:logged-in *session*) (throw (Exception. "Access denied!"))))
#'user/foo
user> (defn bar [] (foo))
#'user/bar
user> (defn quux [] (bar))
#'user/quux
user> (quux)
; Evaluation aborted. ;; Access denied!
The behavior of quux
depends implicitly on the session having a value, but you wouldn't know that unless you dug down through every function quux
calls, and every function those functions call. Imagine a call chain 10 or 20 levels deep, with one function at the bottom depending on *session*
. Have fun debugging that.
If instead you had (defn foo [session] ...)
, (defn bar [session] ...)
, (defn quux [session] ...)
, it would be immediately obvious to you that if you call quux
, you'd better have a session ready.
Personally, I would use explicit arguments unless I had a strong, sane default value that tons of functions used, that I planned to very rarely or never rebind. (e.g. it would be silly to pass STDOUT around as an explicit argument to every function that wants to print anything.)