Fork me on GitHub
#clojure-spec
<
2017-06-08
>
bbrinck02:06:02

Is it expected that maps will match cat specs?

(s/def ::kv (s/cat :k keyword? :v any?))
(s/explain ::kv {"foo" "bar"})
;; In: [0] val: ["foo" "bar"] fails spec: :radiator-react-native.error-messages-test/kv at: [:k] predicate: keyword?

bbrinck02:06:01

I find it a little confusing because my original data doesn’t contain ["foo" "bar"] anywhere

Alex Miller (Clojure team)02:06:01

regex ops match seqable things. maps are seqable and return 2-tuples of k and v

Alex Miller (Clojure team)02:06:20

user=> (first {"foo" "bar"})
["foo" "bar"]

Alex Miller (Clojure team)02:06:49

^ your data does contain [“foo” “bar”] when viewed as a seq

bbrinck02:06:03

Correct me if I’m wrong, but maps are intended to be unordered, right? And regexp ops are about specifying an order? When might I use a regex to validate a map?

bbrinck02:06:15

I suppose if I have a map with zero or one pair, it is ordered and I could use a regex sequence to describe it.

bbrinck02:06:56

For context, I’m trying to write a pretty-printer that uses explain-data. One part of the pretty printer is a way to highlight where the invalid data “lives” in a larger tree of data. This is tricky in this case (and maybe others) because the :val and :in no longer make sense in the context of the original data, but it’s not clear to me how to unwind this transformation or even figure out it occurred.

Alex Miller (Clojure team)04:06:55

I’m not saying you should use a regex op to spec a map, just explaining how spec interprets that :)

Alex Miller (Clojure team)04:06:25

In: [0] says it’s the 0th element of the collection that is the problem. in a map the elements are kv pairs and its this kv pair itself that is indicating the problem (not the particular key or value). what other “in” value would help find it better?

Alex Miller (Clojure team)04:06:49

I guess you could constrain the type of the collection that works with regex op specs more to only be sequential?. Then you would get a predicate error at the map level.

Alex Miller (Clojure team)04:06:51

Something like: In: [] val {“foo” “bar”} fails spec :… at [] predicate: sequential?

Alex Miller (Clojure team)04:06:01

oh, the other thing is that in the latest version of Clojure spec (not sure if cljs is synced up but I think so), you get an extra key :value in the explain-data that is the original root value

pithyless09:06:29

(spec-tools/explain-data (data-spec/spec ::foo {:foo string?}) {:foo 42})
 Unhandled java.lang.IllegalArgumentException
Don't know how to create ISeq from: clojure.lang.Keyword

pithyless09:06:11

^ spec-tools seems really useful, but the error messages are useless. Am I missing something? Was this a regression introduced in alpha16?

pithyless09:06:21

^ maybe @ikitommi can offer some advice?

pithyless09:06:15

ok, so it works if I use the keyword directly instead.

pithyless09:06:00

(def foo (data-spec/spec ::foo {:foo string?}))

(spec-tools/explain-data foo {:foo 42}) ;; exception

(spec-tools/explain-data :sample.core$foo/foo {:foo 42}) ;; explain-data works

bbrinck14:06:28

@alexmiller Thanks for the info! > I guess you could constrain the type of the collection that works with regex op specs more to only be sequential? That’s a promising idea. In my own specs, I’ve tried your suggestion and wrapped my cat specs with (s/and sequential? ,,,) and that solves the issue.

bbrinck14:06:35

I wonder what the tradeoffs would be for enforcing this at the spec level? AIUI, we already do enforce predicates in some cases namely:

(s/explain (s/keys) :foo) ; val: :foo fails predicate: map?
There may very well be downsides to requiring the value be sequential?, but a few benefits I can see are: 1. IMHO, the error about not satisfying sequential is clearer to me than an error about a key/value structure. 2. You can get into the case where two maps are equal, but one matches a spec while another does not. https://gist.github.com/bhb/b617354b22cd0508d14ccbab4e6f5585 Admittedly, this is a carefully constructed spec designed to exploit this issue. I’m not sure it’s a practical concern. But the property of “equal values are equally valid for a given spec” would seem like a nice invariant to maintain.

bbrinck14:06:48

I’m happy to open a JIRA for this, if it is helpful 🙂

Alex Miller (Clojure team)14:06:03

@bbrinck I was suggesting we could build the sequential? check into the regex op spec itself

bbrinck14:06:13

Ah, agreed 🙂

bbrinck14:06:30

OK, will do

Alex Miller (Clojure team)14:06:25

maps (and sets) are unordered and thus at odds with the value prop of the regex op specs which are about sequentially ordered collections

Alex Miller (Clojure team)14:06:49

so it seems like a good idea to catch that up front rather than accidentally allow something that creates a weird error

Alex Miller (Clojure team)14:06:13

if you really wanted it, you could always seq a map or set before using it

bbrinck15:06:35

@alexmiller Do you find it helpful for me to link to this conversation in the JIRA ticket?

bbrinck15:06:48

I’ve created https://dev.clojure.org/jira/browse/CLJ-2183. If I’ve missed anything or created the bug improperly, please let me know

seancorfield15:06:54

"Do you find it helpful for me to link to this conversation in the JIRA ticket?" -- this conversation will be gone in a few days due to the 10,000 message limit in Slack's free tier so I'm not sure you can link to it directly.

bbrinck16:06:53

Oh, good point.

bbrinck16:06:09

OK, well hopefully I captured the relevant bits from the conversation in the JIRA ticket.

bmabey18:06:56

Does anyone know of existing specs for Avro schemas? I haven't found any on github yet but I figured someone must have done this already.

bmabey18:06:22

I'm starting to create some now and it is pretty straight forward but I'm not sure how to make a spec conditional on other values in a map. In this case the ::default spec for an avro schema is dependent on the ::type. https://avro.apache.org/docs/1.8.1/spec.html

dergutemoritz19:06:41

@bmabey Check s/multi-spec