4

I've been looking at the if-let and when-let macros, Im having trouble determining what exactly it is that they "do". In particular, the documentation sais :

clojure.core/when-let
([bindings & body])
Macro
  bindings => binding-form test

  When test is true, evaluates body with binding-form bound to the value of test

I thus am somewhat confused about the way macros are documented.

1) What does the "=>" symbol mean ?

2) What does "test" refer to ?

3 Answers 3

4

Direct answer to your questions:

  1. => means "expands to", as in BNF notation. In this case it means that you need two forms: binding-form and the test.
  2. "test" means anything that can be evaluated as bool.

By the way, I think that the docs are unclear or even maybe erroneous here. It is hard (or impossible) to deduce that the two forms constituting the bindings need to be enclosed in a vector. IMHO it should be either when-let ([[bindings] & body]) (the vector shown in the args) or bindings => [binding-form test] (the vector shown in the BNF-like expansion.)

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks ... this is excellent because , the most important thing is understanding the documentation, so that i can understand other methods.
4

It's often helpful when dealing with a macro to call macroexpand and see what the generated code is.

(macroexpand
    '(if-let [x (myfunc)]
       (foo x)
       (bar))

; expands to

(let* [temp__3695__auto__ (myfunc)] 
   (if temp__3695__auto__ (clojure.core/let [x temp__3695__auto__] 
     (foo x)) 
     (bar)))

; the generated symbols are necessary to avoid symbol 
; capture but can confuse. The above is equivalent to:

(let* [ t (myfunc)]
    (if t
       (let [x t]
           (foo x))
       (bar))

So you can see that if-let is a shorthand for "bind local variable to the result of a function call and if that variable is truthy call the first form, else call the other form. The value returned by your function is only available in the 'truthy' branch."

wrt documentation convention

bindings => binding-form test
  1. => reads something like 'is equivalent to'
  2. test is some form that returns a value

For most of these functions, clojuredocs is your friend, example usage often clarify things. If the clojuredocs example doesn't cut it for you, you can add your own

1 Comment

thanks this was definetly useful to me - btw though , I believe => has a precise meaning from reading the other answer. I think it would be good to update (1) and (2) in your answer to be coherent with those of Rafal below.
2

Consider the following code:

(if-let [x (a-function)]
  (do-something-with x) ;; (a-function) returned a truthy result
  (do-something-else)   ;; (a-function) returned nil or false

This is like let, in that x will be bound to the return value of (a-function). This function could return nil or false. In that case, the implicit test fails and (do-something-else) will be evaluated. If x is not nil and not false, (do-something-with x) will be evaluated.

A scenario where this could be useful:

(if-let [user (find-logged-in-user)]
  (do something with logged in user) ;; a user was found
  (redirect to login page)           ;; no user was found

I sometimes use something like the following, to conditionally add keys to a map of options:

(apply merge {:username "joe"
              :email "[email protected]"}
             (when-let [name (find-full-name)] {:name name})
             (when-let [dob (find-date-of-birth)] {:dob dob}))

This results in a map with :username and :email keys, and a :name key if the users' full name was found, plus a :dob key if a date of birth was found.

I hope that makes the use of if-let and when-let clearer.

1 Comment

the third example with the merge-map is a very good illustration thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.