Welcome! Please see the About page for a little more info on how this works.

+4 votes
in Clojure by
edited by

Currently the default value for clojure.core/*assert* is true.

This has some implications for library creators and consumers.

As a library creator you can't just add asserts everywhere to help you on dev/test because it will make most users pay the performance price in production, since they will be running with *asserts* enable.

As a library consumer, since you don't know what libraries are using asserts, you have to always remember to disable them just in case.

This is worsen by the fact that is not easy to disable them globally in Clojure, since assert is a macro that checks *assert*, the value of the var needs to be set before loading any namespace.

On the contrary java makes all assertions disable by default, so library creators don't have to think about this, and the consumers can explicitly enable them at dev time by providing java -ea (enable assertions)

Since I guess changing the default value of *assert* could be problematic because of backwards compatibility, it would maybe be possible to add a debug-assert like is the case of Rust, which will not be on by default.

As I see it, the important part is having a simple invariant checking instruction that we know is not going to impact performance by default, so hardening our code base for test and dev is not coupled to production performance in the default case.

Two other options are better default values for assert, one is false and the other is the value of java.lang.Class desiredAssertionStatus() which seams to return true/false depending on the -ea flag being provided or not, which will be also false by default., but since most Clojure users already rely on assert being true by default this are maybe not an option.

I see real benefits to an addition like debug-assert so that library developers can opt in while testing (and library users can opt in for testing), while application developers can use assert or choose to opt out if they don't want them active in production.
edited by
+1 for `debug-assert`. I believe there absolutely needs to be a generic, reliable way to add assertions to a library with the absolute certainty that they will not end up in anyone's production build by default under any circumstances, except if the user explicitly opts in.

Some checks are clearly desireable during development and testing, but way too expensive to have in production by default, others may be essential in production to avoid potential data corruption and complex propagating failures.

Library authors should have the ability to choose where to draw that line, it should not be an all or nothing proposition, and authors shouldn't be restricted in how thoroughly they validate stuff during development/testing because they have to worry about potentially dumping overzealous, prohibitively expensive checks on the downstream consumer.

And of course the distinction between dev/test-only and production assertions would be very useful to application developers as well.

P.S. The discussion thread on the Clojurians Slack:


I would suggest changing the title to something like 'Add `debug-assert` as a separate, off-by-default operation for expensive dev/test-only assertions' to clarify what's being proposed here.
I'm going to add https://clojuredocs.org/clojure.spec.alpha/assert to the conversation since that is off by default (at runtime, but can be turned on at runtime for testing or can be completely disabled at compile time as well).

The only problem with recommending this as the library approach is that you are left at the mercy of Spec failures since there's no option for a custom message, like regular assert.
If I understand, you would have debug-assert for asserting only at dev/test time. And then you would have regular assert for asserts you want on in production.

This is starting to feel a bit like logging to me. Could it be possible to add "levels" similar to log-levels to the current assert function?
I'm proposing debug-assert just not to break backwards compatibility of assert. I don't think assert as it is should be used for anything production related neither since they can be disabled. I think for checking important stuff in our code we should be using our normal (when-not something (throw ...)).
The whole purpose of debug-assert is to have what assert is in java, something that you can "abuse" in dev for checking your invariants but that you are sure will not end up in production by mistake and make users of your code pay the perf price.

So I don't see levels in this, just a dev tool.

Please log in or register to answer this question.