I understand that they're different since one works for setting *compile-path*
and one doesn't. However, I need help with why they're different.
let creates a new scope with the given bindings, but binding...?
Thanks!
I understand that they're different since one works for setting *compile-path*
and one doesn't. However, I need help with why they're different.
let creates a new scope with the given bindings, but binding...?
Thanks!
binding
binds a value to a name in the per-thread global environment
As you mentioned, let
creates a new scope for said bindings.
let
creates a lexically scoped immutable alias for some value. binding
creates a dynamically scoped binding for some Var
.
Dynamic binding means that the code inside your binding
form and any code which that code calls (even if not in the local lexical scope) will see the new binding.
Given:
user> (def x 0)
#'user/x
binding
actually creates a dynamic binding for a Var
but let
only shadows the var with a local alias:
user> (binding [x 1] (var-get #'x))
1
user> (let [x 1] (var-get #'x))
0
binding
can use qualified names (since it operates on Var
s) and let
can't:
user> (binding [user/x 1] (var-get #'x))
1
user> (let [user/x 1] (var-get #'x))
; Evaluation aborted.
;; Can't let qualified name: user/x
let
-introduced bindings are not mutable. binding
-introduced bindings are thread-locally mutable:
user> (binding [x 1] (set! x 2) x)
2
user> (let [x 1] (set! x 2) x)
; Evaluation aborted.
;; Invalid assignment target
Lexical vs. dynamic binding:
user> (defn foo [] (println x))
#'user/foo
user> (binding [x 1] (foo))
1
nil
user> (let [x 1] (foo))
0
nil