Rich Comment Blocks
The three main types of comments in Clojure are
- comment
- discard comment
- comment macro (
Rich Comment
)
The last one, the Rich Comment
, is a pretty cool feature of Clojure.
Comment
The first type of comment is a literal comment
; I'm a comment
Anything that follows the ;
is ignored by Clojure until the end of the line. A common use for the comment
is to help future humans understand our code better.
Discard Comment
The second type of comment is a discard comment
(-> 5 inc inc inc) ; 8
(-> 5 inc #_ inc inc) ; 7
In the above code, the #_
makes it as if the second inc
doesn't exist. This is great for debugging because the discard
comment doesn't return a value. In addition to this, there are two additional usage notes about the discard comment
.
The first is that they nest:
(-> 5 #_ inc #_ inc inc) ; you could discard each form in turn
(-> 5 #_ #_ inc inc inc) ; or you could stack them
Here are some examples of where you might find the discard comment
useful:
(or #_ (int? 2) (nil? "Thomas"))
(let [my-number 5
#_ #_ another-number 13]
;...
)
{#_ #_ :name "Between Two Parens" :host "Thomas"}
The second take away is that you don't have to add spaces after the discard comment
:
;; these all produce the same result
(-> 5 #_ inc #_ inc inc) ; space
(-> 5 #_inc #_inc inc) ; no space
(-> 5 #_ #_ inc inc inc) ; space
(-> 5 #_#_inc inc inc) ; no space
The difference between adding the space or removing the space is which one you find more readable.
Rich Comment
Finally, we have the comment macro
which is more affectionatley known as a Rich Comment Block
:
(comment
; everything in here is ignored...returns nil
)
The first time I heard of a Rich Comment
was in Stuart Halloway's excellent talk Running With Scissors where he notes:
Yet, even after watching Running With Scissors
the use of the Rich Comment
hadn't started to click yet. Two more things would need to happen: The first, I would witness REPL Driven Development used in person by David Nolen. The second, I would start to use REPL Driven Development in my own workflow. When I did these things, I was able to better see the benefits of the comment macro
as
- documentation
- a save point
- code setup
- improved code exploration
- preservation of syntax highlighting
With that, let's review a few examples of the Rich Comment
from real life Clojure codebases.
The first example illusrates the documentation
and save point
ideas.
(comment
(println (sh "ls" "-l"))
(println (sh "ls" "-l" "/no-such-thing"))
(println (sh "sed" "s/[aeiou]/oo/g" :in "hello there\n"))
(println (sh "sed" "s/[aeiou]/oo/g" :in (java.io.StringReader. "hello there\n")))
; ...
)
The above comes from the clojure codebase itself and is a code example of how to use sh. For me, the value is that we have an example of how to use sh
(documentation
) and we have some code ready for us to run through our REPL (a save point
). This idea of having a save point
becomes more powerful in the next example:
(comment
(do
(require '[my.app.db :as app.db])
(require '[my.app.cart :as cart])
(def db (app.db/connection!)))
(cart/add db {:item-name "iPhone"})
; ...more stuffs
)
The above builds on the idea of having a save point
and layers on some code setup
helpers. What the above does is add in a few lines of code which, when run, will provide us with a db connection
. Through this, I can quickly begin interacting with my app's database code and building out features.
Of course, there are other types of setup code that you may want. For example, you might be working on a pure function which is just going to transform some data. In this case, we might setup a comment
like this:
(comment
(refer 'set)
(def xs #{{:a 11 :b 1 :c 1 :d 4}
{:a 2 :b 12 :c 2 :d 6}
{:a 3 :b 3 :c 3 :d 8 :f 42}})
(def ys #{{:a 11 :b 11 :c 11 :e 5}
{:a 12 :b 11 :c 12 :e 3}
{:a 3 :b 3 :c 3 :e 7 }})
(join xs ys)
; ...
)
The above is the example Stuart provided in his talk which provides us with some sample data allowing us to immediately begin using our functions to transform said data.
Conclusion
These are just a few examples of how to use a Rich Comment Block
. The most interesting part of the Rich Comment Block
for me is that it's a tangible example of the pragmatism of Clojure. In this case, the comment macro
provides an additional mechanism for speeding up my workflow and making our code more maintainable overall because of the improved documentation and context we get from these comments.