As well as the classic line comments, Clojure also can comment specific parts of the code structure, even when it run over multiple lines.
;; to comment a whole line and
; to add a comment after the start of a line
(comment ) wraps forms and returns
nil when evaluated, referred to as rich comments
#_ to ignore the next form as if it has not been written, commonly used for debugging
Add general documentation for a namespace, such as a comment header that describes the overall purpose of a namespace.
Separate a namespace into logical sections to aid navigation and help identify opportunities to refactor a namespace as it grows.
(comment ,,,) function is used to included code that is only run by the developer directly.
(comment (map + [1 2 3] [1 2 3]))
comment function returns
nil so its advised not to use it inside another form. For example:
(map + [1 2 3] (comment [1 2 3])) ; nil will be passed to map as the third argument
This will fail as it tries to use the
+ function to add
#_ is the appropriate comment style for this example
comment expression is referred to a a rich comment, as it is often used to evaluate expressions it contains as part of a REPL driven development workflow.
Unlike line comments, forms inside a comment block can be evaluated in a Clojure aware editor to help the developer work with a project.
Rich comment are useful for rapidly iterating over different design decisions by including the same function but with different implementations. Hide clj-kondo linter](/clojure-cli/install/install-clojure.html#clj-kondo-static-analyser--linter) warnings for redefined vars (
defn) when using this approach.
The expressions can represent example function for using the project, such as starting/restarting the system, updating the database, etc.
Expressions in rich comment blocks can also represent how to use a namespace API, providing examples of arguments to supply to further convey meaning to the code.
These rich comments make a project more accessible and easier to use.
The "Rich" in the name also refers to Rich Hickey, the author and benevolent leader of the Clojure language.
#_ is the comment reader macro that instructs the Clojure reader to completely ignore the next form, as if it had never been written.
No value is returned, so this comment is safe to use within an expression.
You can place
#_ before the start of a form and everything inside that form will be commented
#_(def my-data [1 2 3 4 5])
#_ will comment forms that span multiple lines, for example function definitions
(str "I am an experiment, so not always needed"))
#_ can also be put on the line(s) before the Clojure form, which can make your code more readable and keep alignment of your code consistent.
As the comment macro can be used without returning a value, it can safely be added to code to help with debugging.
This code example finds the most common word in the text of a book. Most of the lines of code in the threading macro have been commented to discover what the non-commented code does.
As each expression in the threading macros is understood, by looking at its results, comments can be removed to understand more of the code.
(defn most-common-words [book]
(re-seq #"[a-zA-Z0-9|']+" ,,,)
#_(map #(clojure.string/lower-case %))
This is an effective way to deconstruct parts of a larger Clojure expression.
Watch episode #13 of Practicalli Clojure study group to see this in practice.
#_ tells the reader to ignore the next form, it is therefore never evaluated and neither is the
#_. This means that
#_ can be used inside a nested form to comment just a part of the expression
In this example the third vector of values is not read by the Clojure reader and therefore is not passed as an argument to
+ function by
(map + [1 2 3] [4 5 6] #_[7 8 9])
The comment reader macro has the ability to stack these comments on forms, so using
#_#_ will comment out two successive forms.
let form we can comment out a name binding that is causing problems. As the name and value are both forms, then we use a stacked
#_ to comment both out.
We also do the same in the body of the let, so as to not include the evaluation of the string or
name2 local name in the
(let [name1 "value"
(str "First name is: " name1 #_#_" second name is: " name2