运行使用 leiningen 构建的 uberjar 时默认启用 Clojure 应用程序中的断言

Jur*_*nka 0 clojure

将 Clojure 应用程序作为 jar 运行时,是否应该默认启用断言?

我们使用 leiningen 构建一个 uberjar 然后java -jar ...运行它,我刚刚发现这*assert*是真的。

我找不到这个动态变量应该保持什么默认值,但我认为它是假的(并且只在 REPL 开发环境中设置为真)。

这导致了一个令人讨厌的问题,future其中前提条件断言错误导致未来线程死亡,我们不知道发生了什么(因为我们只捕获了Exceptionnot Throwable)。

我浏览了的源代码,clojure.lang.RT但我无法弄清楚*assert*var在哪里设置为 true。

我还发现选项:global-varsleinigen示例项目(这是在提到如何禁用Clojure的断言,包括先决条件?)。这看起来很合理,但我认为对于“生产”构建,我会*assert* false自动获得。

编辑:我错过了T用于*assert*RT.java. 但是,仍然很好奇为什么这是默认设置以及关闭断言的推荐方法是什么(如果甚至推荐的话)。

Ala*_*son 6

从源代码来看,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))))))))
Run Code Online (Sandbox Code Playgroud)

这意味着alter-var-rootbinding都不能改变 的行为assert,因为它们在运行时运行,在assert已经评估之后*assert*。因此,中的:global-vars选项project.clj

  :global-vars {*warn-on-reflection* false
                *assert* false }
Run Code Online (Sandbox Code Playgroud)

是唯一可行的解​​决方案,因为它在宏扩展之前进行评估。使用此测试代码:

(dotest
  (spyxx *assert*)
  (assert false "Don't do that!")
  (println "past the assertion"))
Run Code Online (Sandbox Code Playgroud)

我们得到结果:

----------------------------------
   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
Run Code Online (Sandbox Code Playgroud)