BT

New Early adopter or innovator? InfoQ has been working on some new features for you. Learn more

Clojure.spec is a New Contract System for Clojure

| by Sergio De Simone Follow 5 Followers on May 29, 2016. Estimated reading time: 2 minutes |

Clojure has a new core library, clojure.spec, that aims to provide a standard and integrated system for the specification and testing of data and functions, writes Rich Hickey, Clojure’s creator. Besides making it possible to automatically validate Clojure code, the new specification system can be also used for a number of tasks such as generative testing, error reporting, destructuring and more.

clojure.spec leverages the notion that specifications are the logical composition of predicates, such as integer? or #(< 42 % 66), through logical operators such as spec/and and spec/or. According to Hickey, clojure.spec draws upon previous work done with contract systems, such as RDF and Racket’s, and others.

For example, a map can be specified calling keys with :req and :opt arguments:

(spec/keys :req [::x ::y (or ::secret (and ::user ::pwd))] :opt [::z])

Note that a map specification does not support specifying what kind of values can be associated to a given keyword. Instead, clojure.spec prefers- and to some extent enforces- the specification of values that can be associated to a namespace keyword under the keyword itself:

(spec/def ::x integer?)
(spec/def ::y integer?)
(spec/def ::z integer?)

Such value specifications are then applied in any map using those same keywords.

Sequences can be specified in clojure.specs by means of regular expressions that describe how predicates match the sequence. Functions can be specified using three separate specs:

  • one for the arguments, seen as a single list;
  • one for the return, seen as a single value;
  • an optional one for the relationship between arguments and return. Such a spec could require, for example, that all keys of an input map be present in the returned map.

You can get more details about how to define Clojure specification using clojure.spec here.

Once you have a specification, you can use it by applying conform to a value to validate it. In case conform returns :clojure.spec/invalid, you can use explain to find out why. Additionally, you can use instrument to wrap a function so it tests its three specs. For testing, you can use run-tests to run a suite of generative tests on an entire namespace; or, gen to construct a test.check compatible generator for a spec.

clojure.spec is not the first attempt at bringing specifications to Clojure. Previously, developers could use Schema and Herbert. A different approach to adding guarantees to Clojure is provided by clojure.typed, a gradual typing library enforcing the concept of compile-time validation.

clojure.spec is available in version 1.9.1/alpha1 of Clojure. You can use it by including the following declaration in your project.clj: [org.clojure/clojure "1.9.0-alpha1"].

Rate this Article

Adoption Stage
Style

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread
Community comments

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Discuss

Login to InfoQ to interact with what matters most to you.


Recover your password...

Follow

Follow your favorite topics and editors

Quick overview of most important highlights in the industry and on the site.

Like

More signal, less noise

Build your own feed by choosing topics you want to read about and editors you want to hear from.

Notifications

Stay up-to-date

Set up your notifications and don't miss out on content that matters to you

BT