if-let conditionally creates a lexical binding, evaluates one branch when the bound expression is logically true, and otherwise evaluates an optional fallback. It combines a single binding with conditional control flow, avoiding a separate let and if. section 3.1.2 section 3.1
Its contract is:
- Write a binding vector containing one binding expression, such as [value expression]. The binding name may use destructuring. section 3.1.2 section 3.1
- Evaluate the expression once and make its result available through the local binding in the then-form. section 3.1.2 section 3.1
- Treat nil and false as false; treat every other result as true. Return nil when the condition is false and no else-form exists. section 3.1.2
- Keep the then-form as one top-level expression; use when-let when multiple body forms should be grouped implicitly. section 3.1.2
Truth testing and fallback
(if-let [n "then"] n "else") ;; "then" (if-let [n false] n "else") ;; "else" (if-let [n false] n) ;; nil section 3.1.2
Counting lines only when a resource exists
(defn loc [resource] (if-let [f (io/resource resource)] (count (s/split-lines (slurp f))) 0)) (total-loc "non-existent" "clojure/core.clj" "clojure/pprint.clj") ;; 7570 section 3.1.2
if-let versus if-some
(if-let [n false] n "else") ;; "else" (if-some [n false] n "else") ;; false section 3.1.2
Listing 3.3. → Local Binding, Lexical Scope, Conditional Assignment
(defmacro if-let ([bindings then]) ([bindings then else)) (defmacro when-let [bindings & body]) (defmacro if-some ([bindings then]) ([bindings then else)) (defmacro when-some [bindings & body])
Compare the compact macro shapes for if-let, when-let, if-some, and when-some. section 3.1.2
