code is data, data is code Having been primarily involved with .Net languages in my career so far, was a new idea to me when I first encountered it in Clojure (and also later in Elixir). homoiconicity If you look it up on wikipedia, you’ll find the usual wordy definition that vaguely makes sense. “…homoiconicity is a property of some programming languages in which the program structure is similar to its syntax, and therefore the program’s internal representation can be inferred by reading the text’s layout…” so, in short: . code is data, data is code quote & eval Take a simple example: this line of code performs a temporary binding (binds x to the value 1) and then increments x to give the return value of 2. So it’s code that can be executed and yields some data. But equally, it can also be thought of as a list with three elements: a named let; symbol a vector with two elements — a symbol named x, and an integer; a list with two elements — a symbol named inc, and a symbol named x. quote You can use the function to take some Clojure code and instead of evaluating it, return it as data. quote sidebar: any F# developer reading this will notice the similarity to code quotations in F#, although the representation you get back is not nearly as easy to manipulate nor is there a built-in way to evaluate it. That said, you do have some options, including: F# Quotation Evaluator , and Vagabond , which is how MBrace executes your code in the cloud eval On the flip side, you have the function. It takes data and executes it as code. eval After you have captured some executable code as data, you can also manipulate it before executing the transformed code. This is where come in. macros Macros for instance, is a unit test framework written with macros. You can do a simple assertion using the ‘is’ macro: clojure.test and contrast this with the error message we get from, say, NUnit. Isn’t it great that the failing expressions are printed out so you can straight away see what was wrong? It’s much more informative than the generic message we get from NUnit, which forces us to dig around and figure out which line of the test failed. Update 23/05/2015: As Vasily pointed out in the comments, there is an assertion library for F# called Unquote which uses F# code quotations (mentioned above) and produces user-friendly error messages similar to clojure.test . It goes to show that, even without macros, just being able to easily capture code as data structures in your language can enable many use cases — Phil Trelford’s Foq mocking library is another good example. Building an assert-equals macro As a process of discovery, let’s see how this can be done via macros. Version 1 To start off, we will define the simplest macro that work: might oops, so that last case didn’t work. That’s because the actual and expected values passed into the macro are code, not the integer value 2. Version 2 So what if we just throw an eval in there? that works, right? right? Well, not quite. Instead of manipulating the data representing our code, we have evaluated them at compile time (macros runs at compile time). You can verify this by using : macroexpand so you can see that our macro has transformed the input code into the boolean value and returned it as code. true Version 3 What we ought to do is return the code we want to execute as data, which we know how to do already — using the function. In the returned code, we also need to error when the assertion fails. quote So starting with the code we want to execute given that: well, we’d want to: compare the evaluated values of actual and expected and throw an if they are not equal AssertionError display the actual expression and expected expression in the error message (inc 1) (+ 0 1) display the evaluated value for actual — 2 so something along the lines of the following, perhaps? Now that we know our endgame we can work backwards to define our macro: See the resemblance? The important thing to note here is that we have quoted the whole block (via the ‘ shorthand). But in order to reference the and expressions and return them as they are, i.e. , we had to certain things using the operator. let actual expected (inc 1), (+ 0 1) selectivelyunquote ~ You can expand the macro and see that it’s semantically identical to the code that we wanted to output: Before we move on, you might be wondering about some of the quote-unquote, unquote-quote actions going on here, so let’s spend a few moments to dwell into them. Outputting the expression to be evaluated actual Remember, the and arguments in our block are the quoted versions of and . actual expected defmacro (inc 1) (+ 0 1) We want to evaluate only once for efficiency, and in case it causes side effects. Which is why we need to evaluate it and bind the result to a symbol. actual In order to generate the output code which will evaluate at runtime, we need to reference the expression in its quoted form, hence . (let [actual-value (inc 1)] …) (inc 1) actual ~actual Note the difference in the expanded code if we don’t unquote . actual without the ~, the generated code would look for a local variable called which will fail because it doesn’t exist. actual Outputting the symbol actual-value In order to output the symbol in the binding we had to write , that is, . actual-value let ~’actual-value (unquote (quote actual-value)) I know, right!? Took me a while to get my head around it too. Q. Can we not just write ? ‘(let [actual-value ~actual] …) A. No, because it’ll translate to which is not a valid let binding. (let [user/actual-value (inc 1)]…) Q. Ok, how about ? ~actual-value A. No, because the macro won’t compile as we’ll be looking for a non-existent local variable inside the scope of . actual-value defmacro Q. Ok.. or ? ‘actual-value A. No, because it’ll translate to which fails at runtime because that’s not a valid syntax for binding. (let [(quote actual-value) (inc 1)]…) Q. So how does work exactly? ~’actual-value A. The following: to capture the symbol (quote actual-value) actual-value unquote the symbol so that it appears as it is in the output code Outputting the and expressions actual expected Finally, when formulating the error message, we also saw and . ‘~actual ‘~expected Here are the expanded code with and without the quote. See the difference? Without the quote, the generated code will have evaluated and printed . (inc 1) FAIL in 2 With the quote, it’d have printed instead, which is what we want. FAIL in (inc 1) Rule of thumb to capture a symbol, use ~’symbol-name to reference an argument to the macro and generate code that will be evaluated at runtime, use ~arg-name to reference an argument to the macro and generate code that quotes it at runtime, use ‘~arg-name Finally, let’s test out our new macro. Sweet! So that’s it? Almost. There’s a minor problem with our macro here — it’s not safe from name collisions on . actual-value Version 4 If you see at the end of a symbol then this is used to automatically generate a new symbol with a random name. This is useful in macros as it keeps the symbols declared in macros from leaking out. # So instead of using in the binding we might do the following instead: ~’actual-value let When expanded, you can see the binding is using a randomly generated symbol : let actual-value__16087__auto__ Not only is this version safer, it’s also more readable without the mind-bending business! (unquote (quote actual-value)) So there, a quick(-ish) introduction to homoiconicity and Clojure macros. Macros are a powerful tool to have in one’s toolbox, and allows you to extend the language in a very natural way as does. I hope you find the idea interesting and I have done the topic justice and explained it clearly enough. clojure.test Feel free to let me know in the comments if anything’s not clear. Links Learn to Learn Don’t learn a syntax, learn to change the way you think The Joy of Clojure 2nd Edition Learn Clojure in Y minutes Learn Clojure macros in Y minutes The weird and wonder characters of Clojure
Share Your Thoughts