tags:

views:

479

answers:

2

When does using if-let rather than let make code look better and does it have any performance impact?

+15  A: 

I guess it should be used when you'd like to reference an if condition's value in the "then" part of the code:

i.e. instead of

(let [result :foo]
  (if result
    (do-something-with result)
    (do-something-else)))

you write:

(if-let [result :foo]
  (do-something-with result)
  (do-something-else))

which is a little neater, and saves you indenting a further level. As far as efficiency goes, you can see that the macro expansion doesn't add much overhead:

(clojure.core/let [temp__4804__auto__ :foo]
  (if temp__4804__auto__
    (clojure.core/let [result temp__4804__auto__]
      (do-something-with result))
    (do-something-else)))

This also illustrates that the binding can't be referred to in the "else" part of the code.

harto
Uh, why the downvote?
harto
Also, it is not possible to have more than 2 forms in the binding vector of if-let. Eg: (if-let [a 20 b nil] (println a)) - does not work!
Bart J
+3  A: 

A good use case for if-let is to remove the need to use anaphora. For example, the Arc programming language provides a macro called aif that allows you to bind a special variable named it within the body of an if form when a given expression evaluates to logical true. We can create the same thing in Clojure:

(defmacro aif [expr & body]
  `(let [~'it ~expr] (if ~'it (do ~@body))))

(aif 42 (println it))
; 42

This is fine and good, except that anaphora do not nest, but if-let does:

(aif 42 (aif 38 [it it]))
;=> [38 38]

(aif 42 [it (aif 38 it)])
;=> [42 38]

(if-let [x 42] (if-let [y 38] [x y]))
;=> [42 38]
fogus