Chapter 2
Advance Your Macro Techniques

Most of the macros you’ve seen so far have been small and straightforward. Wouldn’t it be great if they could all be like that? Unfortunately, as you do more and more with macros, the syntax you know so far can get unwieldy.

What if you had to write an assert macro like the one that comes with Clojure? Given what you know at this point, you’d need to do something like this:

advanced_mechanics/assert_no_syntax_quote.clj
 
(​defmacro​ ​assert​ [x]
 
(​when​ *assert* ​;; check the dynamic var `clojure.core/*assert*` to make sure
 
;; assertions are enabled
 
(​list​ '​when-not​ x
 
(​list​ '​throw
 
(​list​ 'new 'AssertionError
 
(​list​ '​str​ ​"Assert failed: "
 
(​list​ '​pr-str​ (​list​ '​quote​ x))))))))
 
 
user=> (​assert​ (​=​ 1 2))
 
;=> AssertionError Assert failed: (= 1 2) user/eval214 (NO_SOURCE_FILE:1)
 
 
user=> (​assert​ (​=​ 1 1))
 
;=> nil

And this isn’t even a complete solution! We’ve skipped the arity[11] that takes a failure message string, to keep things from getting too ridiculous. But there’s a lot to read and learn here, right?

I don’t know about you, but I find it very hard to parse all those nested lists to discover what’s going to come out in the macroexpansion. Luckily we know about macroexpand from Macroexpansion, so it doesn’t have to stay a mystery for long:

advanced_mechanics/assert_no_syntax_quote_macroexpanded.clj
 
(​macroexpand​ '(​assert​ (​=​ 1 2)))
 
;=> (if (= 1 2)
 
; nil
 
; (do (throw (new AssertionError
 
; (str "Assert failed: "
 
; (pr-str (quote (= 1 2))))))))
 
;;; [indentation for clarity]

How can we do this better? Maybe you already have some ideas about how we can make this code look much more like the code it generates. To do so, we’ll use syntax-quote for the first time.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.97.75