Fork me on GitHub

Is there something in spec that is comparable to string? but for a boolean value?


except #(instance? Boolean %)


@sveri: not yet. Obviously there are several more useful predicates that could go into core. Considering which ones now


@richhickey: Yea, it would be nice to be consistent, much less work for the brain then 馃檪


(spec/def ::foo (spec/cat :kw keyword? :int integer?))
(spec/def ::bar (spec/coll-of ::foo []))
(spec/explain ::bar [[:a 10] [:b 20] [:c "30"]])
;; => val: [[:a 10] [:b 20] [:c "30"]] fails predicate: (coll-checker :spec/foo)
Why doesn't the error reporting go into detail (like: val "30" fails predicate: integer?) Is this intentional?


Hm, is it ok to use ::spec/name for my own specs? Also I have not found the source for ::spec/string, neither by searching github (which is a bit harder, because it ignores "::", nor by looking at the api.


Also, is it correct that ::spec/name has string? as predicate?


@alexmiller: About a week ago you hinted on Reddit at improved error messages for Clojure. Don鈥檛 think anyone鈥檚 said that here but it seems like we just got a peek into how that might be accomplished if all of Clojure.core implements specs.


What's the best way to have fdefs be checked during lein test? Instrument all works at the repl, but seems to not during test.


@mjhamrick: what I鈥檝e done is (clojure.spec.test/check-var #鈥檉n-speced-with-fdef)


@anmonteiro: are you just putting that in each test?


the project where I tried it was pretty small


@mjhamrick: I did put (s/instrument-all) at the top of each test namespace

Alex Miller (Clojure team)14:05:44

@kingoftheknoll: yes, I have done additional work in this area

Alex Miller (Clojure team)14:05:55

@sveri ::spec/name and ::spec/string don't exist - what is that from?


@alexmiller: Thats why I have not found it in the code. Not sure where exactly it came from, its just that cursive offered it via code completion. Maybe I typed it in a different namespace or whatever. Anyway, good to know.


@richhickey @alexmiller: I have another proposed enhancement to explain-data. Several predicates, such as keyword?, or integer? are programmatically easily recognizable via :pred for non-conforming values. It's a straightforward equality check (e.g. (= 'keyword? (:pred error-map))). Other predicates are, to my understanding, more difficult to recognize. Take s/keys and s/tuple for example. In the former, keys yields a predicate when a required key is missing. While the predicate is somewhat understandable when you eye ball it, picking it out programmatically has been error-prone. The same goes for s/tuple when the number of arguments is incorrect.

Alex Miller (Clojure team)14:05:13

an example would help make this specific


Those functions have privileged access to which predicates are failing. It might be helpful to provide named predicates in those cases so that consumers of explain-data could be more intelligent. See -

Alex Miller (Clojure team)14:05:02

thx for the example! :)

Alex Miller (Clojure team)14:05:49

oh the contains stuff that's inside keys

Alex Miller (Clojure team)14:05:25

I'll have to defer that to Rich, I think he's not around atm


It seems to me that inner conformed values are lost when using coll-of or map-of. Example:

(spec/conform (spec/coll-of (spec/and integer?
                                      (spec/conformer (constantly nil)))
              [1 2 3])
returns [1 2 3] instead of [nil nil nil]. Meanwhile, cat and keys preserves them. How come?


@alexmiller: Sure 馃檪 Ill be back later.

Alex Miller (Clojure team)14:05:00

@moxaj Rich said above "currently conform doesn't flow into coll-of, so the value is never conformed, only checked" which I think is likely related to this


@alexmiller alright, thanks!


I am converting a lib from schema to spec and in schema I was able to inline define the return values / args. Is there a way to do that in spec too? The alternative in this case is a lot more code.

Alex Miller (Clojure team)15:05:08

for map keys, no - that's the whole point of the map / attributes split

Alex Miller (Clojure team)15:05:24

the benefit is that you are creating named reusable semantics for ::entityname, ::ns, etc etc

Alex Miller (Clojure team)15:05:57

so you can use those elsewhere too


@alexmiller: Yea, I understand the benefits, just wanted to make sure I did not miss anything


Is it possible to hook ones own error message if a predicate fails? Ex we have schemas that takes a string that should be a valid parse of our internal query language, and if fails should return a nicely structured error with line/col num and a human readable message. With prismatic Schema it is possible to do with our own schema type extending a protocol for explain/spec.


Correct me if I am wrong, but I think so far I can only get a generic "predicate foo? failed" type of message

Alex Miller (Clojure team)15:05:55

there is not currently a way to provide a custom error for a failing predicate

Alex Miller (Clojure team)15:05:00

you can use explain-data to detect problems and produce a custom error message

Alex Miller (Clojure team)15:05:31

but @richhickey can comment on whether that might be something we could do


that's what I suspected. Something like ex-info for specs could be useful

Alex Miller (Clojure team)16:05:40

why not explain-data for that?

Alex Miller (Clojure team)16:05:55

or maybe I misunderstand the suggestion


I actually missed it, that could work yes

Alex Miller (Clojure team)16:05:39

that's what instrument does on a failing function spec


hmm I am not sure that's really equivalent. I would have to wrap all schemas that contains these values with a special validation fn I think. I would like to have my own datastructure returned by explain-data (or something else) when the predicate fails. I am not sure that's doable with the current approach where predicates return just a potentially truthy value.


but I could be wrong. I played for 20min with specs so far.


this might sound like a small concern, but in a larger context it's very useful: we have a whole api around the manipulation of data containing such queries, being able to use the same schema type and framework and not wrap the whole thing because of a single type in a potentially nested Schema is a nice feature, in our case it also integrates for free with frameworks that just follow this Schema format (rest server, swagger etc).


First piece of feedback is that clojure.spec makes me really want 鈥渂oolean?"


@eraserhd: @richhickey said they consider adding this and some more core types (I felt the need for it too :-))


I鈥檓 still playing with it, but the second thing I鈥檓 working through is the repetition, especially for function arguments.

Alex Miller (Clojure team)18:05:19

@eraserhd: we have boolean? in almost every example namespace we wrote. so, agreed. :) definitely near the top of the wanted-predicates list.


Another interesting problem I encountered: I used a set for boolean: #{true false}. But sets aren鈥檛 treated differently in this context, although I might expect that they are. Namely #(#{true false} false) ;=> false. So having a set in a spec which contains nil or false is awkward.

Alex Miller (Clojure team)18:05:58

it is kind of an interesting wrinkle though that the obvious way to write boolean? is with #(instance? Boolean %)


It might at least deserve a call-out in docs.


Also, a lot of things seem to leak their internal implementations wrt error messages.

Alex Miller (Clojure team)18:05:31

but Clojure uses (only) canonical boolean values

Alex Miller (Clojure team)18:05:57

@eraserhd: prob better for a mention in the ref doc (which isn't there yet)


@alexmiller: I encountered a couple. Just a minute and I鈥檒l paste.


Anyone else seeing problems with reloading test namespaces in the REPL (cursive)? I just commented out some tests, reloaded the test ns in the REPL, hit run-tests, but still, all tests were run. I noticed something similar with test-refresh not recognizing commented fdefs. I cannot point at anything right now, but, there seems to be something broken


@cfleming: are there gonna be slick Cursive toolips for providing associated specs when editing functions arguments?


I imagine I'm editing the arg to some function that takes a big map, and as I'm filling in the components of the map its telling me what each piece should conform to


What is the spec for 鈥榤ap? i.e. in core.typed, I鈥檇 write something like (t/ann map [ [ X -> Y] [X] -> [Y] ). i.e. it takes a collection of X, and a function of X->Y, and returns a collection of Y. Is there a way to do that in spec?


I鈥檓 missing something related to recursive specs. I want to define a vaguely hiccup-like structure where the first element is the name, followed by some attributes, followed by a vector of children. What am I doing wrong here?


if you add another (s/spec ....) around the ::tag I get a success, but I am not sure why


I guess you are in the regex context that matches the outer vector, so you need another s/spec to create a new regex context for the list of child vectors, then you need another s/spec to get out of the regex context of the vector of children and specify an individual child


I鈥檇 also be interested to see the spec for clojure.core/map


@hiredman: Ah, thanks! I had to read that a few times, but now it makes sense 馃檪


Ok, I dont understand how to use instrument. My guess was, that if I put (s/instrument-all) into a namespace all functions are instrumented whenever I load the file into the REPL. But thats not the case, instead I have to execute that function everytime after I loaded a namespace.


Also, it works when I put it to the end of a ns


Hi all, first I want to thank Rich&Co for this awesome innovation 馃憤 And I have a question:

(s/def ::even-big-or-small (s/and (s/or :very-big #(> % 1000)
                                        :very-small #(< % 1))
(s/valid? ::even-big-or-small 10000)
;; throws CompilerException java.lang.IllegalArgumentException: Argument must be an integer: [:very-big 10000]
what am I doing wrong?


just noticed, works fine the other way around:

(s/def ::even-big-or-small (s/and even?
                                  (s/or :very-big #(> % 1000)
                                        :very-small #(< % 1))))


@dryewo: in the first case, it鈥檒l conform to :very-big and output [:very-big 1000]


(s/def ::even-big-or-small (s/and (s/or :very-big #(> % 1000)
                                               :very-small #(< % 1))
                                        #(even? (second %))))


even? gets [:very-big 1000] so we are interested in the second element


that鈥檚 the explanation, but I鈥檓 also unsure if it鈥檚 expected


yes, I also got this idea of what鈥檚 happening, but is it the correct behavior?


shouldn鈥檛 s/and be order agnostic?


I鈥檝e read somewhere that it鈥檚 not, by design


but I can鈥檛 recall the reason


I鈥檓 reading the guide: maybe I should first read it to the end before asking more questions 馃檪


thanks, there is even a section about it in the end of the guide, I鈥檒l look into it


Is there a pattern for whether you spec functions or use spec for validation (pre/post-conditions)? There doesn't seem to be a reason for pre/post-conditions if you spec a function.


I dont understand that, I have the code in the following snippet, and it fails with:

(remove-autoinc-columns [{:foo "some_t"}])
ExceptionInfo Call to #'de.sveri.clospcrud.s-play/remove-autoinc-columns did not conform to spec:
At: [:args] val: ([{:foo "some_t"}]) fails predicate: (cat :cols :de.sveri.clospcrud.s-play/columns),  Extra input
:clojure.spec/args  ([{:foo "some_t"}])
  clojure.core/ex-info (core.clj:4617)


@sveri: you need to wrap ::column in s/spec


like this: (s/def ::columns (s/cat :col (s/* (s/spec ::column))))

Alex Miller (Clojure team)22:05:22

@arohner: @anmonteiro here's a spec for map (assumes a seqable? predicate like the one in core.incubator)

Alex Miller (Clojure team)22:05:26

(s/fdef clojure.core/map
  :args (s/cat :f ifn?
               :colls (s/* seqable?))
  :ret (s/or :seq seqable? :transducer ifn?))


simpler than I imagined

Alex Miller (Clojure team)22:05:18

I've left off :fn because I'm lazy but you could also verify some additional things

Alex Miller (Clojure team)22:05:04

like :f / :transducer or :colls / :seq are the valid combos and even things like whether the :ret cardinality is minimum of the input colls cardinality

Alex Miller (Clojure team)22:05:09

but that's enough to detect things like (map inc 100)

Alex Miller (Clojure team)22:05:47

which is the kind of thing that normally leads to IllegalArgumentException Don't know how to create ISeq from: java.lang.Long

Alex Miller (Clojure team)22:05:27

which, if it's occurring in a nested context can be pretty confusing


Anyone given the test namespace a try yet? I鈥檓 trying to figure out how check-var works. It appears to be hanging half the time I try it and passing tests the other half.


@alexmiller: is it possible to check that f鈥檚 input matches the coll?


right now I don鈥檛 see a way to do that


because there doesnt鈥 seem to be a way to 鈥榗ompare鈥 specs

Alex Miller (Clojure team)22:05:24

you would have to use a custom predicate to do so

Alex Miller (Clojure team)22:05:17

the :args spec could be (s/and <current> #(custom predicate on the args))

Alex Miller (Clojure team)22:05:04

I guess you might need to describe :f with an fspec to get the right parts to work with


I鈥檝e created a gist with my attempt to try and use check-var it is returning nil, is that expected behavior?


do you have the test.check library on the classpath?


Yup gen/generate works


@tyler: there is a bug there, I hit it too


I think it is fixed on master


Ah awesome thanks


@alexmiller An example wrt errors: (spec/explain (spec/tuple number?) []) gives an error about #(clojure.core/= (clojure.core/count %) 2).


@eraserhd: "val: [] fails spec: _ predicate: (clojure.core/= (clojure.core/count %) 1)鈥 says the collection should have count == 1