Fork me on GitHub
#clojure-spec
<
2017-03-06
>
jrychter11:03:42

I used s/merge to extend a spec with additional keys, but when I s/conform, it seems that only the newly-added keys get conformed, not the original spec. In general, it seems that while s/valid validates the entire merged spec, s/conform only uses the last spec passed to s/merge. Is this something to be expected?

jrychter11:03:17

Oh, just found CLJ-2033 which describes this exact problem.

jrychter11:03:36

After reading the discussion several times, I don't understand what I'm supposed to do. Is the point here that unqualified keys are second-class citizens and should be phased out? Or is there another solution to merging specs and having conform work?

jrychter11:03:12

Instead of s/merge, right?

mpenet11:03:19

well it's not really merging anymore, but that can fix it depending on your use case

mpenet11:03:39

(s/conform (s/and (s/keys :req-un [::value]) (s/keys)) {:value 5}) -> {:value 5.0}

jrychter11:03:51

And more generally? Because try as I might, I find this behavior unexpected.

jrychter11:03:26

Indeed, s/and works just fine. I'm making notes to never use s/merge, but I don't understand why "it does not flow conformed results". Why would one want it to behave that way?

mpenet11:03:39

not sure really, but yeah I do just like you said and just use s/and

jrychter11:03:17

I'm sure there was a reason, but to explain my thinking: having read both the s/merge docstring and the clojure.spec guide, I did not expect s/merge to be a lossy operation which will drop some of my conformers. Especially since it is called just like a map merge operation and looks like one. If this is really intended, I think it deserves a warning in both places.

mpenet11:03:25

with and you also loose :gen

mpenet11:03:15

so yeah, it's one of the oddities in spec. I also find this quite counter-intuitive (no matter the reason/motivation behind this)

peeja16:03:03

Is there a way to ask if one spec conforms to another?

peeja16:03:37

That is, "Is every value which is valid for spec A valid for spec B?"

not-raspberry16:03:09

I think in general case this is impossible, not only in spec. User-defined functions can be passed to s/def. But in a limited way, you can generate values for spec A and validate them against spec B.

peeja16:03:30

I guess that makes sense. One of the major visions for spec is to confirm compatibility between, say, your code and a new version of a dependency (in a world where they both are well spec'd). Is the expected way to do that to use test.check to confirm it works for lots of random values?

gfredericks16:03:09

I don't think so

gfredericks16:03:41

I think the main idea was static analysis of keysets and regexes

peeja16:03:48

So you are expected to be able to do some degree of static analysis, then

bronsa17:03:21

I think specs can theoretically be comparable in finite time, since AFAICT they describe regular languages

bronsa17:03:46

but it might take a long time to compare them

bronsa17:03:12

I might be wrong tho. if spec accepts CFGs then comparing specs is definitely not possible

not-raspberry17:03:11

@bronsa What about (s/def ::a (fn some-fn [v] ...)) and (s/def ::b (fn different-fn [v] ...)) - how do you compare Clojure functions?

bronsa17:03:28

you don't, you're right

bronsa17:03:12

so it's a theoretical no too :)

gfredericks17:03:29

unless you can get away with saying "different functions are always completely different"

gfredericks17:03:44

@bronsa the sequence regexes aren't technically regular as they can self-reference

gfredericks17:03:50

I'm not sure if that's an intentional feature though

bronsa17:03:11

¯\(ツ)

souenzzo19:03:09

How can I express: "One of there keys are required"???

souenzzo19:03:10

(s/def ::car (s/keys :req [:document/number :license/plate])) But I just need one of these keys

Alex Miller (Clojure team)19:03:50

You can use or in :req - check the doc string or the guide

seancorfield20:03:05

(s/def ::car (s/keys :req [(or :document/number :license/plate)])) — note this allows for cars with both document number and license plate so if you specifically want exclusive-or, you need to s/and another check onto that.