This illustrates why working with Clojure feels so relaxing and elegant.
Most languages operate on code as text. When commenting out code with //, it's easy to mistakenly leave out a line containing a closing bracket for example. When using /* , you have to manually insert the closing * / at the exact right spot.
On the other hand, #_ simply operates on the logical form that follows it, instead of operating blindly on characters. You know it's going to do the right thing whether you want to comment a long multiline form, or a single function call in the middle of a line.
Using structural editing (Paredit) to navigate and reorganize code is an incredible experience for the same reasons.
I'm one of these people that doesn't feel "flow" or get in the "zone" when working (leading me to sometimes wonder what I'm missing out on, or if I'm lacking something, although my career is fine so far). But writing Clojure is probably as close as I can get. :)
As one not knowledgeable about Clojure, and to play devil's advocate: one of the handy parts about `//` is that you can violate the language rules. E.g. I've fairly often had cases where I want to temporarily remove a check, to see if something behaves as I expect:
Or in other cases collapse two if/else blocks together, or stuff like that. It's not as common as commenting out a logical unit, definitely, but it's far from uncommon.
How would you achieve that in Clojure? Seems like you'd need to copy/paste, like this?
Yes, you could. Also, most lisp/clojure editing modes will have commands for manipulating S-expressions, such as slurp and barf, which make it a single shortcut to move `thing` out of the `if` expression in your example.
makes it quite simple to leave the tests in. Also, quite easy to raise forms (structurally raise) and reevaluate the form and then undo but not reevaluate the form to have it modified.
Common mistake. For non-lispers: Macros evaluate from the outside, which means the defroutes macro will expand before the (comment ...) macro. For this to reliably work, you need a reader macro that removes the code before macro expansion. I don't know if clojure has that, but common lisp and some schemes have utilities for it.
The comment macro should really come with a warning that it should only be used as a top level form. Using it inline (a very natural thing to do if you're coming from a language with more typical block comments!) only ever leads to suffering, in my experience.
I notice I accidently do similiar thing with parenedit. I can accidently move forms in and out of where they should be. Not an issue if the functions are small but with longer ones I might slurp off screen.
I notice default syntax highlighting in Emacs, Vim, and VSCode make that odd-one-out "GET" a different color than the rest which would make this a lot easier to catch than otherwise.
; and ;; pretty usage is same as Common Lisp. #_ is replaced with #+nil in Common Lisp which is just a reader macro. ;;; is usually reserved for prose, and of course there's #| commenthere |# which is just another reader macro, and is suitable for code examples, where you can probably still eval it in your text editor.
A macro that takes any number of arguments and does absolutely nothing. This is still a macro invocation, so the arguments must not cause a reader error.
I sometimes teach macro writing basics at work, with exercises -- writing this macro is always Exercise One.
It is a common pitfall to write non-readable content in a comment expression, which can certainly be confusing to newcomers who are used to less stringent multiline comments like /* ... */ or triple-quoted strings in Python.
I don't know if it's a voluntary feature, or if it was just faster to implement that way, but personally I see it as an advantage.
Rich comments are not just the equivalent of a multiligne comments in other languages, I expect the statements inside of it to be run, often many times, during normal clojure development. I don't want to have broken code inside.
I think it makes sense, because there are two types of comments here. First is "ignore everything" which is handled by ";" but then there is the function "comment" or "rich comment" that should still be valid code and all dependencies it needs available. If not, someone couldn't open the file and run the forms inside the block as-is, so the program is not valid.
It's a gotcha, but in the end I think it's neat that it makes sure it's valid.
linked from the article is a segment from "Running With Scissors: Live Coding With Data" (Stuart Halloway at Strange Loop 2018) that describes in more detail how Rich Comments can help w/ interactive development
I use this a lot in REPL driven development when combined with tests, each time I save the file all my tests run. But sometimes I don't want certain blocks of code to run or compiled as they are just there to be sent to the REPL for my own testing / development.
I’ve been professionally working with clojure for the last few years and never understood the comment block use cases.
Of course I might be missing some obvious advantages but it seems to me that it is better to invest the time in turning these comments into tests rather than having them thrown randomly in source files.
I mean eventually all these comment blocks are just test cases aren’t they? We use them to evaluate expressions and compare the output value to our expectations.
When I want to explore I build a small test case and use the fast feedback loop to have it as interactive as possible.
Would be happy to hear any thoughts on this.
What does "save point" mean in this context? The concept is mentioned several times in the article, but I didn't see any references to saving anything.
OK, I think I get it now. So comment macros saved from an earlier REPL session can be brought back for use later? That's pretty cool, and it does highlight the LISP roots of Clojure.
I just started a new job last week on a team using Clojure so I am setting aside Common Lisp and getting my mind back into Clojure for the foreseeable future.
Using 'comment' is cool, I hadn't used in in my previous Clojure life, but as HN manishsharan said here, putting macro expressions inside 'comment' can cause problems.
It feels good to be back in the Clojure community but I also have to admit I miss not using Common Lisp every day.
Everything seems faster in CL, both in repl interactions and super fast startup of CL applications. That said, both are beautiful languages that spark joy to use.
I don't believe there is a video of this. I took an in person course hosted by David Nolen a while ago where I witnessed, in person, D Nolen working. The course was a CLJS Masterclass.
I prefer to use the discard comment `#_` for everything that I'd use the rich comment `comment` macro for. As far as I know, there's no advantage to the `comment` macro over `#_`.
I think `comment` is nice if you have an editor that doesn't syntax highlight and let you structurally edit discard comments. But in my Emacs setup, code that is after a discard comment still gets all highlighting and syntax editing and evaluation as any other code, so I don't feel a need to ever user `comment` macro over it.
This is confusing to me. How is this better than tests that do the exact same work (document how to use a function, and provide setup to make iterating on a function easy)?
The difference is solely on the workflow. Using the rich comment approach you setup some state, fiddle around, change a function, invoke it again, store some arguments in a variable, change the function again, split it into two functions and so on.
It is advised that once things stabilize you take your learnings and stuff them into a unit test for posterity.
It's not better if you have an environment that allows easy iterative function development.
This is just a way to achieve that. However, combined with some of the other clojure niceties (namely cider and structural editing) it does make it a better experience for me.
It allows me to maintain a better flow as I can maintain REPL state if needed(especially if it's a quick hack where dependency injection like component isn't worth the overhead). When I'm done exercising the code I can just make minimal changes to make the comment a test, leave it in place, or move it over to a bag-of-tricks user.clj.
Clojure's very slow startup forces you to this workflow, relying entirely on the REPL to compensate. It's not any better compared to a language with a fast change-test-debug cycle.
That's not true. There are plenty of other Lisp dialects with a faster startup time - Chez, Fennel, CL, etc. You still would want REPL-driven-workflow. Practically, it's the other way around: Clojure's slow startup time doesn't matter because it's a Lisp, and no other non-homoiconic language (except maybe Smalltalk) gives you the productivity boost that "true REPL" allows, no matter how fast change/test/debug cycle is. Because it's not just about fast cycle, with non-homoiconic languages that do not have "true REPLs" you also have to think about the program's state and other things.
Homoiconicity of Lisp allows you to evaluate any expression or sub-expression without any kind of ceremony. Other languages do not have the luxury of giving you the answer right away. There's always some "ritual" involved, automated or not, but it is still required, but in a Lisp connected to a REPL, you immediately get the answers.
I have gotten myself into trouble have a syntax error, etc in my comment body. I kept thinking that piece of code is “commented out” and shouldn’t cause issues!
Very poor choice of words for a title. I was under the impression that using a "rich comment" it will block (the code execution) - a bug. Only upon reading the article I realized the true meaning.
Most languages operate on code as text. When commenting out code with //, it's easy to mistakenly leave out a line containing a closing bracket for example. When using /* , you have to manually insert the closing * / at the exact right spot.
On the other hand, #_ simply operates on the logical form that follows it, instead of operating blindly on characters. You know it's going to do the right thing whether you want to comment a long multiline form, or a single function call in the middle of a line.
Using structural editing (Paredit) to navigate and reorganize code is an incredible experience for the same reasons.
I'm one of these people that doesn't feel "flow" or get in the "zone" when working (leading me to sometimes wonder what I'm missing out on, or if I'm lacking something, although my career is fine so far). But writing Clojure is probably as close as I can get. :)