Fork me on GitHub

@misha thanks for this solution. I did that in a way for something a bit different and the problem I bumped into was that you cannot require the namespace containing the specs in another namespace and use it with a shortcut. Let's say the previous code was in a namespace a.

(ns b
  (:require [myapp.lib.a :as a]))

(s/valid? ::a/foo <whatever>)

(s/valid? :quz/resource <whatever>) <-- I have to remember that this comes from namespace myapp.lib.a
and doing this
(ns b)

(s/valid? :quz/resource <whatever>)
the dependency graph of spec definitions is not right and the compiler will complain (it happened to me and I spent time renaming a lot of specs) Thus, even though I can do it, I tend to feel that it's a clumsy solution.


tying all specs' ns to file ns - is often not a good idea


Another question that comes to my mind, how can I validate a map whose keys are string (typically data from an HTML form). Doing this (s/def ::form-data (s/keys :req ["foo" "bar"])) is half of the spec. I'd like to qualify the content of the keys. Again I feel like missing a syntax like this: (s/def ::form-data (s/keys :req [(s/key "foo" string?) (s/key "bar" int?)])).


i keep running into an issue with managing the complexity of my specs, and was wondering whether i'm "doing it all wrong". specifically, of quite a few specs, i need to have multiple variations of the same "schema", depending on the context. to give an example, a user should not need to have an ID before it is inserted into the database, but it does need an ID when it is. this is a simple example, but this pattern repeats. since ideally, i want my code to be able to declare whether it expects a a "stored user" or not, i currently compose these things as follows:

(s/def :user (s/keys ...))
(s/def :user/inserted (s/merge :user (s/keys ...))
on the surface this seemed like a good idea, but after a while of using this, i discovered downsides to this. most importantly: as soon as you have other specs that depend upon inserted users or not (e.g. a "company" vs "inserted company"), you repeat this pattern a lot, even when there is not necessarily a difference between a "company" and "inserted company". as an alternative to this, i was thinking of making the state an explicit property i can multi-spec on. this makes the approach more data-driven. but then i wouldn't be able to directly say, "i expect an inserted user" in the code through specs anymore. are there any alternatives to this ? i hope my question is making a bit of sense 🙂


now, code cannot just fdef anymore saying it expects a ::shape/cube or a ::shape/sphere, it can only fdef on ::shape


this is another discussion on the same topic =>


@lmergen I think Rich Hickey has noticed that problem, too


he talked about it at the conj and hinted at a big change to spec to make this easier


yeah I saw that, sounds very promising!


basically, you define a map spec separately from the selection


which lets you separate out the definition of the entity from the context


yes so you declare what you need rather than what something is


ok thanks I kind of forgot about that


i have faced this same problem myself


proliferation of specs because, for instance, if you have all the CRUD operations, they each require slightly different data


though you'd like to think of them as operating on the same entity


it’s the same problems that type systems without extensible records have


so now spec becomes a category system :)


what’s that


sorry I meant category as in category theory


rather than describing types you describe traits


I am fairly sure I have just mentioned a few forbidden words


— awkward silence —

Alex Miller (Clojure team)17:01:06

I think it’s most useful to think of it as oriented around value sets, as described by predicates


I’ll be watching your progress alex, just found the new spec repo

Alex Miller (Clojure team)17:01:12

maps are composites of their attributes and the key is that semantics are derived from the attributes, not from the composite itself


so they become self describing ?

Alex Miller (Clojure team)17:01:38

not sure that’s the important bit

Alex Miller (Clojure team)17:01:00

the new idea from Rich’s last keynote is that different functions can speak more precisely about which subset of the composite it cares about, and we can have better tools for describing what a function does with those inputs wrt to the output