read


read
or learn more

Trammel version 0.7.0 (reference invariants++)

Apr 6, 2012

Trammel is a Clojure providing contracts programming (sometimes called “Design by Contract” or DbC) capabilities. Features of Trammel currently include:

  • Contracts on functions
  • Composable contracts
  • Post-definition function contract application
  • defrecord and deftype invariants
  • Reference type invariants (i.e. Agents, Atoms, Refs, and Vars)
  • Ability to turn-off checks in a production setting
  • Support for Clojure versions 1.3 and 1.4

Trammel is inspired by Eiffel and Racket.

Absorb

You can use Trammel in your Leiningen and Cake projects with the following :dependencies directive in your project.clj file:

    [trammel "0.7.0]

For Maven-driven projects, use the following slice of XML in your pom.xml‘s <dependencies> section:

<dependency>
  <groupId>org.clojure</groupId>
  <artifactId>trammel</artifactId>
  <version>0.7.0</version>
</dependency>

Enjoy!

Places

Changes from version 0.6.0

  • Better assertion error reporting
  • Ability to add constraint descriptions used in assertion reporting
  • Constrained defrecords no longer support default field values
  • Constrained defrecords no longer generate keyword args ctor function
  • Reference type invariants

Reference type invariants work in the following ways.

Atoms

Atoms are created directly with their invariants:

(def a (constrained-atom 0
         "only numbers allowed"
         [number?]))

@a 
;=> 0

And checked on change:

(swap! a inc)
;=> 1

Invariant violations are reported right away:

(swap! a str)
; Pre-condition failure: only numbers allowed 

(compare-and-set! a 0 "a")
; Pre-condition failure: only numbers allowed 

Refs

Refs are created directly with their invariants:

(def r (constrained-ref 0
         "only numbers allowed"
         [number?]))

And also checked on change, within a transaction:

(dosync (alter r inc))
;=> 1

(dosync (alter r str))
; Pre-condition failure: only numbers allowed 

Vars

Vars are created directly with their invariants:

(defconstrainedvar ^:dynamic foo 0
  "only numbers allowed in Var foo"
  [number?])

Var invariants are checked on rebinding, such as with binding:

(binding [foo :a] [foo])
; Pre-condition failure: only numbers allowed 

Agents

Agents are created directly with their invariants:

(def ag (constrained-agent 0
         "only numbers allowed"
         [number?]))

And are checked on send and send-off

(send ag str)
(agent-error ag)

However, the invariant violations are reported consistently with the agent setup. In this case, the errors are accessible via the agent-error function.

Plans

The following capabilities are under design, development, or consideration for future versions of Trammel:

  • Contracts for higher-order functions
  • Better error messages
  • defconstraint — with ability to relax requires and tighten ensures
  • Modify macros to also allow regular Clojure constraint maps
  • Allow other stand-alones: true/false, numbers, characters, regexes
  • Marrying test.generative with Trammel
  • More documentation and examples

More planning is needed around capabilities not listed nor thought of.

2 Comments, Comment or Ping

  1. Caspar Hasenclever

    Interesting lib!

    Did you mean “You can use trammel” instead of “You can use core.cache” in the first sentence in “Absorb”?

    Cheers,

    Caspar

  2. Sam Tobin-Hochstadt

    We just call it Racket, no “Scheme” required.

Reply to “Trammel version 0.7.0 (reference invariants++)”