One of the new features in Clojure 1.10 is tap. The changelog describes it as follows:
tap is a shared, globally accessible system for distributing a series of informational or diagnostic values to a set of (presumably effectful) handler functions. It can be used as a better debug
prn
, or for facilities like logging etc.
tap>
sends a value to the set of taps. Taps can be added withadd-tap
and will be called with any value sent totap>
. The tap function may (briefly) block (e.g. for streams) and will never impede calls totap>
, but blocking indefinitely may cause tap values to be dropped. If no taps are registered,tap>
discards. Remove taps withremove-tap
.
I’m already using it as a better debug prn! I’m using Cursive and I
connect to a REPL launched by Boot. With my setup, (prn :DEBUG value)
has two potential downsides.
- The output may go either to the Boot terminal or to the Cursive IDE depending on the code path.
- The output is not pretty-printed.
Tap allows me to solve both problems. I want my debug prints to always appear in Cursive’s REPL, so after starting the REPL, I add a tap handler by running this command:1
(add-tap (bound-fn* puget.printer/cprint))
Here bound-fn* ensures that
the output goes to Cursive and not to the terminal. Puget is the
pretty-printer I’m used to, but you can replace it with your favorite printer.
If you do not want to add new deps, you can use clojure.pprint
or even plain
old prn
:
(add-tap (bound-fn* clojure.pprint/pprint))
(add-tap (bound-fn* prn))
Now when I want to debug-print something, I do (tap> "hello world")
. Since
both tap>
and add-tap
are in clojure.core
, I don’t need to require
anything. I can just tap>
away.
Another debugging trick is to store the tapped value in an atom. I’ve used this only once so far, but it was pretty handy. Setup:
(def debug-a (atom nil))
(add-tap #(reset! debug-a %))
Now I can tap>
an intermediate value in the middle of some complicated code
and then poke at it in the REPL via @debug-a
. Ideally you’d use
a debugger, but if you are in hurry, maybe tap is enough.
-
I don’t know how to do this automatically. If somebody knows, please tell me. ↩︎