Sharpsign Plus Reader Macros
They’re called reader macros. Reader macros in Common Lisp are a read-time
feature that lets you do a pre-compile condition check. The
for a feature, and if it succeeds, then the S expression following it is
evaluated. If not, the code never even gets passed to the compiler. It is as
if it never existed. They’re kinda like the
ifndef macros in
C/C++. They’re there to let you define an expression if a feature exists.
Why would I ever do that?
Let’s say you want to do something only if the quicklisp feature is present.
Rather than writing a function that looks at
*features* to see if
is in the feature list, and having that check compiled into your code and
running every time you run your code, you could do something like this:
If quicklisp is in
do-something-with-quicklisp gets handed
to the compiler. If not, none of that code ever even makes it to the compiler.
It’s filtered out when the file is read, hence the name.
Okay, the question remains, what is the
I use it to get the same functionality that one might get from the
#_ in Clojure. It
checks the condition
(or), which, with no arguments, will always return NIL.
It’s a condition that can never pass, so the expression immediately following it
will never make it to the compiled output in real life. It will never exist in
your shipped binary, but you can evaluate the expression in your repl all day.
It’s nice if you’re doing REPL dev in your editor and add some function to mess
with something that should never exist in the final product. I leave them in my
code if I need to mess with something from time-to-time (external api call
behavior checks, etc.). Here’s an example.
#+(or) (defun try-broke-ass-thing () "Runs broke-ass-thing. This will never exist anywhere but my dev repl." (let ((test-arg1 "some random argument") (test-arg2 "another random argument")) (inspect (broke-ass-thing test-arg1 test-arg2)))) (defun broke-ass-thing (arg1, arg2) "This function is broken. We want to fix it." ... some-value-that-is-unexpected)
try-broke-ass-thingfunction is a function I might write to target the
broke-ass-thingis misbehaving or needs some love in some way. Maybe it’s calling an API for which I am trying to figure out the response shape or something.
I can load the whole file into my repl and manually evaluate
try-broke-ass-thing as I tweak the code. When I finish tweaking, I can leave
the definitions. If I ever need to use those again, they’re there, but they
never ship with the final binary.
Is it a hack? Probably. Would tests be better? Yes. Will I keep doing this? Absolutely when I need something quick and dirty.