Fork me on GitHub
Oliver George03:06:53

New favourite spec trick. Wrap your spec to generate warnings instead of erroring out.

(defn warn
  "Throw warning if spec is invalid but always pass."
  (fn [x] (when-not (s/valid? spec x)
            (js/console.warn (s/explain-str spec x) x))

Oliver George06:06:23

And now not. Turns out the stack trace from normal errors is more informative (cljs).


I have within one ns two different specs for :db/id (one for data coming from datascript and one for datomic ids). How can I specify this in spec?


How would you specify a "vector of anything"?


(coll-of ??? [])


What goes in the ??? position?


Is there some sort of top-level type in spec?


I guess I could just use vector?, but I'd like it ideally to generate lots of random Clojure things to go in the vector.


Similarly, what about a map where the keys can be anything but the vals are more restricted?


(map-of ??? integer?)


@puzzler: (spec/coll-of ::spec/any [])


Hmmm, looks like that conforms non-vectors too.


Where is ::spec/any documented?


@puzzler: (s/spec vector?)?

Alex Miller (Clojure team)12:06:28

There is new support for this in next alpha


I have a lot of vector?-based specs that currently all require custom generators.

Alex Miller (Clojure team)12:06:51

coll-of has many new options

Alex Miller (Clojure team)12:06:47

Can now indicate the expected incoming type separately from the conformed and generated type

Alex Miller (Clojure team)12:06:22

Also, Rich added s/merge yesterday to create spec that merges multiple map-validating specs and will gen as you expect (union of keys)

Alex Miller (Clojure team)12:06:20

@jannis in next alpha you will be able to do (s/coll-of int? :kind []) to indicate a vector of ints


When a spec is complicated and composed of many component specs, I'm having trouble figuring out, stylistically, which of those component specs to register to namespaced keys, versus just def'ing them to regular vars. Any tips on this?


It seems to me that when spec'ing a bunch of optional keywords for a function, to get good error messages I really want to be able to say "These are the only keys allowed in this map of optional keywords and values". Is there any way to do that?

Alex Miller (Clojure team)13:06:00

generally, I think you should not def anything to a regular var

Alex Miller (Clojure team)13:06:36

and you should register specs for all map attributes and for any major “types"

Alex Miller (Clojure team)13:06:58

anything recursive will require registration at the recursion points

Alex Miller (Clojure team)13:06:33

and you might want to register things at a finer granularity if you find it gives you more meaningful explain errors

Alex Miller (Clojure team)13:06:39

re restricted key sets - no, this is intentionally not provided, but you can s/and a constraint like #(every? #{:allowed :keys :in :map} (keys %))


Thanks. Early on, I predicted that a lot of people would re-invent slightly different definitions of validating or conforming combined with assertions in the event of a failure, and I've been seeing that happen. Is something along the lines of assert-conform and assert-valid? likely to make it into a future alpha?

Alex Miller (Clojure team)14:06:13

yes, there are likely to be a conform-ex and some kind of assert, but I don’t think those will be in next alpha


I've been wanting to add an extended :reason to certain specs, especially if they have strange interdependencies


If you look sideways at this you could see the possibility of specs with composable prose explanations


Super quick question: If I’m referencing a spec in another namespace, do I need to :require that namespace too?


I’m finding the app runs fine in the REPL, but at compilation, it can’t resolve the specs.


If I'm understanding you correctly, all specs need to be required before use


in order for the registry to populate


Okay, I was afraid of that 😉


So, form-validation & clojure.spec, I assume people have tried it already, are there any writeups/snippets?


@bhauman: @kendall.buchanan I find it interesting that this can create an implicit dependency between namespaces that is not declared via the ns form, maybe for "good style" you should require the ns containing the spec even if you don't need to (technically)?


I’ll admit – I still find the coupling between specs and namespaces odd. Namespaced keywords seem to make sense when you’re trying to define a domain path, but sometimes those domain paths don’t match your namespace hierarchy. But Clojure basically says it has to.


Still struggling to understand it. But, seems fine.


@kendall.buchanan: you are aware that you don't have to use an existing namespace correct?


just a namespaced keyword


Yeah, totally, but I guess I’m struggling to see the established path forward.


> but sometimes those domain paths don’t match your namespace hierarchy


👍 (same struggle here)


In terms of dependency management, I think if people look at the way they did plumatic/schema or any add hoc type validation.


it's like any dependency


We've started defining a lot of our specs in a separate heirarchy. It's a bit early to tell how well that works but thus far it's been pretty useful in terms of reducing circular dependency issues, making specs equally usable in tests and code, etc.


@bhauman, would you recommend (or consider as a viable path) to always use domain-based keywords school/:type and eschewing ::type (contained in Just ditching the latter pattern?


So that's one possibility, is to use ::type but to place those definitions in a namespace that is a little descriptive of the domain model.


I wouldn't be the one to ask, but I would say no


A possiblity: As long as your keys are distinct, you can keep it all in one file.


@angusiguess: Kind of like That’s more or less what I’ve done for objects that cut across many domains.


@kendall.buchanan: That's precisely what I do, including a namespace for more generic types.



or similar.


Yeah, exactly what we’ve started doing.


Then if we have aggregates that our functions take we'll define them in the function's namespace.


And I think it works well. I guess I like the ::thing syntax, for brevity, and realize it ties things up into the namespace. I guess we’re learning as we’re going, though.


(By the way, I have no proposed alternative, so not complaining. Just been a source of friction for me.)


Defining everything in-line bit us pretty quick.


Right, @angusiguess… which, I have to say, clojure.spec is what it claims: built for composability. I’ve been a heavy Schema user, and have to say, I’m getting more reuse out of spec by far.

Alex Miller (Clojure team)22:06:13

Clojure 1.9.0-alpha8 is now out with lots and lots of spec updates


Lots of new spec stuff in alpha 8 - conforming coll support, plus count/kind control, instrument can generate stubs, gen/spec overrides in instrument/test, merge keys specs


wow sounds good