Fork me on GitHub

can I use a multispec on a vector of tags, instead of just a single keyword?


how would I write such a defmulti?


(defmulti event-type
  (fn [m] (->> m :event/type (into #{}))))


here's what I came up with


turns the vector of tags into a set, so the multispec can use the set as a predicate function for the multimethod dispatch


this way I can combine multiple defmethods. If we take the example of :event/type from the official clojure spec guide, then I could do:

{:event/type [:event/search :event/error]
 :event/timestamp 1463970123000
 :error/message "Invalid host"
 :error/code 500
 :search/url ""}


and so both :event/search and :event/error would be valid specs

Alex Miller (Clojure team)01:02:04

Yeah, there are no constraints on multi-spec as long as you follow the pattern


In docs for s/keys there is “Note: there is no support for inline value specification, by design.”. Does some expanded explanation of this exist somethere?


is it possible to specify spec for value referred by specific key in the map? I.e I want to say that {:id “my-id”} “my-id” should be validated by spec ::resource-id


currently if you use s/keys there is only implicit assignment of the spec in case the keys are same

Alex Miller (Clojure team)02:02:20

re the second question, the key must match the spec name

Alex Miller (Clojure team)02:02:51

the idea here (also in the rationale) is that we are assigning enduring semantics to an attribute that can be used throughout the system

Alex Miller (Clojure team)02:02:17

it is admittedly a different philosophy than something like Schema


yeah, but it is quite hard to work with the external data which shape you don’t control


for example, {:id “res-1” :name “My resource 1” :sub {:id “sub-res-1” “Sub-resource 1"}}


should I use synthesized keys for registering specs or I need to mimic data structure with packages structures?


It is so tempting to use :: for specs registration


for example above I would like to register two specs: ::resource-id and ::sub-resource-id in the same namespace

Alex Miller (Clojure team)03:02:54

well you can certainly do that along with s/keys and :req-un which will only match the name part, not the namespace part


yes, it is possible but in this case you need either give it synthesized (not existing) namespace part like :rest-resources/id and :rest-resources.subresource/id or literally create ‘subresource’ package and define ::id spec there


both of these are far from ideal


having s/vcat would definitely be quite helpful


especially if you could unform back to a vector

Alex Miller (Clojure team)13:02:41

Rich is as well I think but hasn't decided how it should be implemented yet


how do people feel about something like this:

(defn coerce
  [spec data]
  (let [conformed (s/conform spec data)]
     (if (= :clojure.spec/invalid conformed)
       (s/unform spec conformed))))
I've been avoiding conform == coerce, after getting bitten, but this has got me thinking of dabbling again.


I wish the :gen overrides of stest/instrument behaved the same way as the :gen of stest/check


right now you can only use it for functions which have been stubbed


hey all, quick q about how instrument and check work in cljs. I’m running a figwheel repl in cursive. the repl is choking and timing out when I eval an instrument or check call for an fdef‘ed function . further evaluations – even of simple forms (e.g. (+ 1 1) – then result in an eval timeout. posted in the figwheel channel already but feel like I might just be misunderstanding a core spec concept and how I’m supposed to use it

Alex Miller (Clojure team)18:02:03

instrument should not take a long time to execute

Alex Miller (Clojure team)18:02:36

check certainly can take a while as it runs 1000 tests by default - you can change that by passing it additional options. although most often adjusting your generators is what really needs to happen.


yeah it feels like I must be doing something wrong. fwiw my spec is just a set of a few dozen string values (i.e. (cljs.spec/def ::my-spec #{”something” “something-else” …}). my fdef looks something like

(cljs.spec/fdef my-bool-returning-func
  :args (s/cat :my-spec-val ::my-spec)
  :ret boolean?)
simply calling "cljs.spec.test/instrument `my-bool-returning-func” or “cljs.spec.test/check `my-bool-returning-func” causes the same choking behavior


don’t know if that’s idiomatic/correct or not


I am looking at using spec for validation for a SPA app. I am hoping that I can use the same specs for both the front and backend. I am guessing that I would place them in a cljc file, but I was wondering how the s/def would work with s referring to clojure.spec and cljs.spec. Any ideas?


what’s the preferred idiom to “optionalize” some map with :req keys? specifically, something like (s/merge ::foo (s/or ::bar (s/keys)))


that is, defining a new spec that is a ::foo and optionally also a ::bar

Alex Miller (Clojure team)22:02:53

@assoc-in the new cljs feature for automatic aliasing means that I think you can just use the clojure namespace in the cljc file and it will work for both

Alex Miller (Clojure team)22:02:02

but you should check with David in #clojurescript

Alex Miller (Clojure team)22:02:41

@bbloom not sure I understand what you’re asking?


@alexmiller to make a simplification of what i’m doing concrete: imagine i have some spec (s/def ::syntax (s/keys :req [::line ::column])) and i have some other AST nodes that might or might not have line/column information on it: (s/def ::ast (s/keys :req [::type ::op ::whatever] :opt [::line ::column]))


however, i have it’s not just two fields, it’s quite a few and i want to basically say “an ast node is these keys and optionally a ::syntax"


is that clearer?

Alex Miller (Clojure team)22:02:19

you could define ::syntax with :opt instead and just s/merge?


ideally not, since the parser requires everything be a ::syntax with proper line and column info


right now i’m doing s/or with an empty (s/keys)

Alex Miller (Clojure team)22:02:54

then why did you say optionally above?

Alex Miller (Clojure team)22:02:06

in that case, just merge ::syntax and ::ast ?


there’s two parts of the system


@alexmiller okay thanks I'll ask


the parser requires all the output have ::syntax, and the analyzer allows it


ie not every node that comes out of the analyzer has line/col info on it - but in the parser, it is required


i don’t really want :opt tho, since if there is a ::line, i expect there to also be a ::column


they aren’t individually optional


hence (s/def ::ast (s/merge (s/keys :req [.....]) (s/or ::syntax (s/keys)))

Alex Miller (Clojure team)22:02:57

why do you need to do anything in the analyzer? the s/keys you already have in ::ast will validate those


b/c it only analyzes them independently


so if i do (assoc foo ::line 1) that should be a problem b/c there’s no column


the s/or doesn’t really solve that problem tho


the s/or does help generation tho

Alex Miller (Clojure team)22:02:51

I don’t think there is a way to do it in keys, so you’d need an extra constraint


i figured as much 🙂 was wondering if there was a particular pattern that has been successful for this sort of thing

Alex Miller (Clojure team)22:02:49

don’t think I’ve seen it

Alex Miller (Clojure team)22:02:35

I think I would leave the :opt in ::ast to get gen and and that with a custom predicate

Alex Miller (Clojure team)22:02:15

the pred should filter any generated maps that don’t satisfy the pred


it feels like a symmetric operation to s/?


or maybe s/nilable


would that work? (s/merge (s/keys …) (s/nilable ::syntax))


ah, sadly not


well wait… hmmm maybe it sorta does? just doesn’t seem to do what i’d want in gen


@alexmiller Thanks I asked David and he said I can just use clojure.spec everywhere in the cljc file and I'll be good to go. I am really happy to see that spec's will be usable across both clojurescript and clojure so easily


that’s a pretty minimal repo of a shortcoming of generate on s/merge with s/nilable