Fork me on GitHub

@alexmiller: super useful screencast thanks again! One thing I've not quite grokked yet is the full relationship between spec and test.check... I understand it's a dev time dependency for the generators... but should you ever be using raw clojure.test generator functions? Or should you use spec as a wrapper or use both?


I noticed that spec lazy-loaded test.check underneath too... not sure what the purpose of that is

Alex Miller (Clojure team)13:08:34

spec.gen relies on test.check and exposes most of its generator functions

Alex Miller (Clojure team)13:08:31

This anything that uses generators will require a dependency on test.check (we expect that to primarily be a test time dependency)

Alex Miller (Clojure team)13:08:42

spec.gen wraps those functions to dynamically load them though, allowing you to build generators without incurring a load-time dependency on test.check

Alex Miller (Clojure team)13:08:41

So you should always prefer using spec.gen as that lets you use specs in other ways without incurring that dependency

Alex Miller (Clojure team)13:08:32

Maybe this itself would be a good blog topic :)


What is the reason :ret is not checked by t/instrument?


man we need some kind of canonical link for that question


t/instrument is designed to help you ensure that you’re calling functions correctly, according to spec. Checking that functions (yours or someone else’s) are implemented correctly is a different job, handled by st/check.


Could pin that ^


not sure how well this will play with our history constraints


amend it with "please re-say&pin this message each morning"


I see plenty of old things pinned on other channels


@rickmoynihan: we use test.chuck for additional generators and we've taken the same approach of loading it dynamically as a test-only dependency /cc @alexmiller


Yeah, I think pinned stuff sticks around.


@seancorfield: you just generated a bunch of lazy vars?


theres is some documentation update planned regarding this issue @alexmiller? Something the community could help you with? Sorry if the docs were already amended with this point, I didn't re-read them lately


alexmiller: thanks for the enlightening answer... And I think it would be another great blog topic 🙂


seancorfield: yeah test.chuck is awesome (thanks gfredericks btw) how do you load it as a test time dependency only? Do you mean just through a dev/test profile? Or do you mean you're reusing core.specs lazy loading things somehow.


re :ret it in fact says it in the guide -- I think people have a false expectation of the tool to behave in a certain symmetric (for lack of a better term) way. But the real distinction is about development (`instrument` - :ret) vs test (`check` + :ret) time. As you know dev time vs test time is a little blurrier in a REPL.


if you think of it (and teach it to people!) in terms of that distinction, it becomes intuitive

Alex Miller (Clojure team)16:08:36

@andrewhr sorry, what issue are you referring to? (several things in this channel)

Alex Miller (Clojure team)16:08:35

the guide is updated with each alpha so should be in sync

Alex Miller (Clojure team)16:08:11

guide discusses it, docstrings I think are up to date. where else should it be?


great! It's a pretty common question and we've not sure if the docs were up to date.. sorry for my laziness in not checking there before asking you

Alex Miller (Clojure team)16:08:18

I started working on a reference page for spec which will be kind of somewhere between the docstrings and the guide, eventually I’ll get around to finishing that


looks promising! thanks for working on that 🙂


@rickmoynihan: we wrap stuff we need to use in a function like this

(defn fn-string-from-regex
  "Return a function that produces a generator for the given
  regular expression string."
  (fn []
    (require '[com.gfredericks.test.chuck.generators :as xgen])
    (let [string-from-regex (resolve 'xgen/string-from-regex)]
      (string-from-regex regex))))
/cc @gfredericks


In my build.boot file I have

(deftask testing-context
  "Provide main testing context."
  (merge-env! :dependencies '[[com.gfredericks/test.chuck "0.2.7" :scope "test"
                               :exclusions [*/*]]
                              [javax.servlet/servlet-api "2.5" :scope "test"]
                              [org.clojure/test.check "0.9.0" :scope "test"]])


that task is chained in ahead of any testing tasks, to make the libraries available, but scoped so they don’t end up in artifacts (in case a build test accidentally got chained in with a testing task).


how do you say in spec: map of keywords and arbitrary values


(s/map-of keyword? (constantly true))?


sorry if I'm asking the obvious, but why are there both or and alt? alt is used in sequences, but why isn't or used there?

Alex Miller (Clojure team)18:08:40

this is covered briefly in the guide btw

Alex Miller (Clojure team)18:08:03

alt describes alternatives that are in the context of a sequence

Alex Miller (Clojure team)18:08:46

a spec with alt can thus be reused in different regex op contexts

Alex Miller (Clojure team)18:08:02

whereas or represents a spec for a single value

Alex Miller (Clojure team)18:08:39

there are situations where either would give you the same result but then there are cases where they would not

Alex Miller (Clojure team)18:08:25

it’s better to start from the direction of what you’re spec’ing - if it is syntax in a sequential context, then use alt, otherwise use or

Alex Miller (Clojure team)18:08:57

(s/conform (s/* (s/alt :n number? :k keyword?)) [5 :a 10 :b 20 :c])

Alex Miller (Clojure team)18:08:25

you are describing the structure / syntax of a sequential structure there

Alex Miller (Clojure team)18:08:43

(note that you can’t use s/or here)


@alexmiller: thanks for explaining - I tried to find it in the guide, but couldn't understand it as clear as you explain it now

Alex Miller (Clojure team)18:08:27

(s/conform (s/or :n number? :k keyword?) 100)

Alex Miller (Clojure team)18:08:40

here you’re describing a single value - use s/or


Is there any reason to avoid using (s/tuple …) for the :args value of s/fdef?


repl=> (s/conform (s/* (s/alt :n number? :k keyword?)) [5 :a 10 :b 20 :c])
[[:n 5] [:k :a] [:n 10] [:k :b] [:n 20] [:k :c]]
repl=> (s/conform (s/* (s/or :n number? :k keyword?)) [5 :a 10 :b 20 :c])
[[:n 5] [:k :a] [:n 10] [:k :b] [:n 20] [:k :c]]


both just work

Alex Miller (Clojure team)18:08:22

but regex forms like cat are preferred

Alex Miller (Clojure team)18:08:45

b/c the conformed result will tag the arguments (which tuples don’t)

Alex Miller (Clojure team)18:08:07

again, this is syntax (the syntax of a function) so that’s a better match



repl=> (s/conform (s/* (s/or :n (s/* number?) :s (s/* string?))) [[1 2 3]])
[[:n [1 2 3]]]
repl=> (s/conform (s/* (s/alt :n (s/* number?) :s (s/* string?))) [[1 2 3]])

StackOverflowError   clojure.core/implements? (core_deftype.clj:539)


did I break something? 😉

Alex Miller (Clojure team)18:08:49

I can’t spot anything immediately that would make that result acceptable :)

Alex Miller (Clojure team)18:08:23

I would not expect that value to actually satisfy that spec though

Alex Miller (Clojure team)18:08:45

you are describing sequences like [1 2 3 “a” “b” 4 5 6 “d” “e”]


yeah, weird right?

Alex Miller (Clojure team)18:08:19

whereas the first s/or spec is for sequences like [[1 2 3] [“a” “b”] [4 5 6] [“d” “e”]]

Alex Miller (Clojure team)18:08:40

if you can file a jira, that would be useful


ah, then I found a good example to explain the difference?

Alex Miller (Clojure team)18:08:36

really, I don’t think I would use s/or to describe either of those two kinds of inputs

Alex Miller (Clojure team)18:08:09

well, it might make sense, it really depends on semantics


How would you describe

[[1 2 3] [“a” “b”] [4 5 6] [“d” “e”]]


Jira ticket coming btw

Alex Miller (Clojure team)18:08:01

(s/conform (s/* (s/spec (s/alt :n (s/* number?) :s (s/* string?)))) [[1 2 3] ["a" "b"] [4 5 6]])

Alex Miller (Clojure team)18:08:10

or you could do (s/conform (s/* (s/or :n (s/coll-of number?) :s (s/coll-of string?))) [[1 2 3] ["a" "b"] [4 5 6]])


I would choose the second probably too


(s/conform (s/* (s/spec (s/alt :n (s/* number?) :s (s/* string?)))) [[1 2 3]])
;;=> [[:n [1 2 3]]]


@alexmiller: so was the bug that I missed the surrounding s/spec?


The guide says: "If you need to spec a nested sequential collection, you must use an explicit call to spec to start a new nested regex context. "

Alex Miller (Clojure team)18:08:49

well I mean I’d say that was your error

Alex Miller (Clojure team)18:08:02

but it’s a bug that you got a stackoverflow :)


garbage in, garbage out 😉

Alex Miller (Clojure team)18:08:15

it should have just said invalid

Alex Miller (Clojure team)18:08:27

it wasn't garbage though, just not accurate


is there an equivalent of declare but for specs?


@stathissideris: you don't need to declare keywords before using them


seancorfield: Thanks... at first the require in that function makes me wince... but it's actually a nice trick being able to include the generator in the spec and use the spec in production context without the generator dependency. Nice! xgen/string-from-regex is too nice to use! 🙂


I use runtime require quite a bit. Very useful for conditional dependencies etc.


I seem to recall that s/atom-of was bandied about shortly after clojure.spec was released. Is that something we should anticipate in core or has it been discarded as a bad idea?


My current use case calls for like an s/promise-of, but I’m curious what the thinking is wrt specs for async values

Alex Miller (Clojure team)22:08:12

it was never bandied about by anyone from core :)

Alex Miller (Clojure team)22:08:17

I think it’s a bad idea