Assertions in Clojure applications enabled by default when running uberjar built with leiningen

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



Assertions in Clojure applications enabled by default when running uberjar built with leiningen



Should assertions be enabled by default when running a Clojure application as a jar?



We use leiningen to build an uberjar and then java -jar ... to run it and I've just found out that *assert* is true.


java -jar ...


*assert*



I couldn't find what default value should this dynamic variable hold but I thought it would be false (and only set to true in REPL development environment).



This lead to a nasty issue in combination with future where a precondition assertion error caused the future thread to die and we didn't know what happened (because we caught only Exception not Throwable).


future


Exception


Throwable



I went through the source code of clojure.lang.RT but I couldn't figure out where is the *assert* var set to true.


clojure.lang.RT


*assert*



I've also found the option :global-vars in the leinigen sample project (this is mentioned in How to disable Clojure assertions, including preconditions?).
That looks reasonable but I thought that for "production" build I would get *assert* false automatically.


:global-vars


*assert* false



EDIT: I missed that little T thing (boolean true) used to initialize *assert* variable in RT.java. However, still curious why that's the default and what is the recommended way to turn off assertions (if it's even recommended).


T


*assert*


RT.java





Ok, I missed that little T thing (boolean true) used to initialize *assert* variable in RT.java. However, still curious why that's the default and what is the recommended way to turn off assertions (if it's even recommended).
– Juraj Martinka
Aug 10 at 17:58


T


*assert*


RT.java




1 Answer
1



From the source, clojure.core/assert is a macro that evaluates *assert* at compile time:


clojure.core/assert


*assert*


(defmacro assert
"Evaluates expr and throws an exception if it does not evaluate to
logical true."
:added "1.0"
([x]
(when *assert*
`(when-not ~x
(throw (new AssertionError (str "Assert failed: " (pr-str '~x)))))))
([x message]
(when *assert*
`(when-not ~x
(throw (new AssertionError (str "Assert failed: " ~message "n" (pr-str '~x))))))))



This means that both alter-var-root and binding cannot change the behavior of assert, since they operate at runtime, after assert has already evaluated *assert*. Therefore, the :global-vars option in project.clj:


alter-var-root


binding


assert


assert


*assert*


:global-vars


project.clj


:global-vars *warn-on-reflection* false
*assert* false



is the only solution that will work, since it is evaluated before macro expansion. With this test code:


(dotest
(spyxx *assert*)
(assert false "Don't do that!")
(println "past the assertion"))



we get result:


----------------------------------
Clojure 1.9.0 Java 10.0.1
----------------------------------

lein test tst.demo.core
*assert* => <#java.lang.Boolean false>
past the assertion

Ran 2 tests containing 0 assertions.
0 failures, 0 errors.
lein test 32.28s user 0.56s system 349% cpu 9.387 total






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard