A few days into learning clojure, I thought it would be a good idea to look at some actual clojure projects in github. I was feeling all confident and what not – you know getting used to lispy way of writing things. The purpose of going through some code, was to get a gist of what was going on in the code, if not understanding it fully. I guess you already know where this is going don’t you ? Yep, I find myself reading through code and I find these two,
->> (and a lot more scary stuff) staring at me, and I had no clue what to make of it. I guess there would at least be a few of you guys who felt the same.
Apparently, they are called threading macros.
-> is the thread first and
->> thread last macros, and they are syntactical sugar to your code. It makes reading/writing code easier. “Meh! Just that?” you ask. Let’s see.
Let say you want to do this (divide 2 by 1 then subtract 3 then add 4 and multiply with 5). How would you write it in clojure?
Boy! It can get difficult to read when you have a bunch of these strung together.
Now lets see how we write it with
Woh! This is a lot simpler to read (at least for me)! So what happens here is the thread first macro just takes the 2 and then pass it as the first argument to the next function and then the result of that as the first argument to the next and so on.
Thread last does something similar, instead of passing it as the first argument it would pass it as the last argument. So if you where to apply the
->> to the previous example you would get
My favourite use of the threading macros has been when I have used them with java/clojure data structures. It makes handling them a lot easier.
The thread-last macro
->> is very useful in dealing with collections. Where you have to transform them or apply functions to them, which is what you might be doing in a lot of your clojure code. For example, if you have this collection:
Say you want to add a new ‘\n’ at the end of each line and then print them together as a single string. How would you do this? Well its easy, you just get the text and then apply map and reduce to it and then print. Let’s write it shall we?
Now lets take a look at this if we decide to write it using thread last macro
It’s a lot more cleaner, and you don’t have to keep matching the parenthesis to actually figure out what is happening. This works even better when you want to do a lot more transformation on the collections.
While at it, we can make use of this neat function
get-in that helps you get values from deep inside a map, which is somewhat better to use at times. The advantage of using
get-in over the threading would be that it helps you supply a
not-found value, the would be returned if the key you are looking for is not there in the collection. Pretty neat huh? Let’s try that.
Now if you are working with java interop and you aren’t using the thread-first macro, then this might change your mind. Let’s take this example, where you have a java object and you apply a series of methods on the Java object or Java objects returned on applying these methods. This is how you would be doing it.
Now with thread first this becomes
Which is way more easier to read, and write. It is aligned with the original java representation, which aids in better understanding of the code. It feels less clunky than the previous case where you could get lost in all those parenthesis.
Since we are at it, let’s talk about another function:
doto. This is very helpful when you have to apply multiple functions on a single java object. We didn’t use it in the previous example because, each of the functions were returning a different object.
Consider you have a table-border object and you want to set border to it. This is how you would be writing with thread the
You could use the threading operator or even write it in a single line, but it would be messy.
A threading macro can be used to reverse the read order: the value is primarily for people reading your code later; if using a threading macro doesn’t feel like it will make your code easier for the next person to read, it’s probably the wrong choice.