Skip to content

junjiemars/assertions

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

assertions

Zero penalty runtime assertions for Clojure.

Clojure’s built in assert macro is a compile-time construct that will eliminate assertions if *assert* is set to false. However, there isn’t a good way to set *assert* to false. You cannot set! it in your namespace, because that will fail when your code is loaded in any context where there isn’t an established binding for *assert* (AOT’ed code for one). Otherwise you could try to alter-var-root *assert* in a user.clj file, but that does not compose well. You can set a Java system property to configure some features of the Clojure compiler, but there doesn’t exist a property for disabling assertions.

Even if you could work that all out, what you have is still a compile-time assertion construct. Java’s assertions have the property that they can be enabled/disabled at runtime without any performance penalty.

My assertions work similar to Java’s. There is a pjstadig.Assertions class with a static final field that is initialized by calling desiredAssertionStatus for that class. When this static final field set to false and it is used in a conditional, then the body of that conditional (i.e. the assertion) is eliminated as dead code by the JIT.

To use this for a Leiningen project

[pjstadig/assertions "0.1.0"]

Or for a Maven project

<dependency>
  <groupId>pjstadig</groupId>
  <artifactId>assertions</artifactId>
  <version>0.1.0</version>
</dependency>

Example:

(ns pjstadig.assertions.test
  (:refer-clojure :exclude [assert])
  (:require [pjstadig.assertions :refer [assert]]))

(defn -main [& [flag]]
  (assert (not= flag "fail")))

When you run the program with assertions enabled it throws an AssertionError:

~/src/assertions$ JVM_OPTS=-ea lein run -m pjstadig.assertions.test fail
Exception in thread "main" java.lang.AssertionError: (not= flag "fail")
        at pjstadig.assertions.test$_main.doInvoke(test.clj:14)
        at clojure.lang.RestFn.invoke(RestFn.java:408)
        at clojure.lang.Var.invoke(Var.java:415)
        at user$eval33.invoke(NO_SOURCE_FILE:1)
        at clojure.lang.Compiler.eval(Compiler.java:6619)
        at clojure.lang.Compiler.eval(Compiler.java:6609)
        at clojure.lang.Compiler.eval(Compiler.java:6582)
        at clojure.core$eval.invoke(core.clj:2852)
        at clojure.main$eval_opt.invoke(main.clj:308)
        at clojure.main$initialize.invoke(main.clj:327)
        at clojure.main$null_opt.invoke(main.clj:362)
        at clojure.main$main.doInvoke(main.clj:440)
        at clojure.lang.RestFn.invoke(RestFn.java:421)
        at clojure.lang.Var.invoke(Var.java:419)
        at clojure.lang.AFn.applyToHelper(AFn.java:163)
        at clojure.lang.Var.applyTo(Var.java:532)
        at clojure.main.main(main.java:37)

When you run it with assertions disabled no AssertionError is thrown, and there is no penalty for including assertions in your code:

~/src/assertions$ lein run -m pjstadig.assertions.test fail
~/src/assertions$ 

You can also enable/disable assertions specifically for the pjstadig package (e.g. -ea:pjstadig...), or the pjstadig.Assertions (e.g. -ea:pjstadig.Assertions) class. However, doing so will enable/disable assertions globally for any namespace that is using these assertions. There is currently no way to enable/disable assertions for individual Clojure namespaces.

License

Copyright © 2013 Paul Stadig. All rights reserved.

This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at http://mozilla.org/MPL/2.0/.

This Source Code Form is "Incompatible With Secondary Licenses", as defined
by the Mozilla Public License, v. 2.0.

About

Zero penalty runtime assertions for Clojure.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Clojure 72.7%
  • Emacs Lisp 16.8%
  • Java 10.5%