Fork me on GitHub

So this is a spec error I ran into today and Im here thinking there must be a better way to get to the root of the problem


what’s on line 28 in bootstrap/feature.clj? is that your project?


(defn- feature-dispatch [[k v]] k)


it’s probably the destructuring of the first arg, maybe a keyword is being passed as the first arg


^ I was able to solve this the problem was (spec/explain-data ::feature-gate feature) when I needed (spec/explain-data ::feature-gate [feature])


@alexmiller do you plan to support this for spec-alpha2 as well? I noticed it does not yet work in CLJS.

Alex Miller (Clojure team)20:02:53

should work, haven’t looked at why yet, but wasn’t intentionally broken


FYI, I just ran out entire test suite against the latest spec2 and there's just one failure (for s/valid? on a large data structure for a very complex, nested spec) -- which was the unexplained failure I had before. The generator problems I mentioned before are fixed by the latest work.


@alexmiller What in spec (or spec2) causes this predicate to be used? (or (nil? %) (sequential? %))


(it's not in our code so I assume it's what underlies s/cat or something?)

Alex Miller (Clojure team)21:02:05

I think that’s checked for all regex specs

Alex Miller (Clojure team)21:02:54

I assume you see that fail?


I've tracked it down a bit further...

(def s [ ... sequence of hash maps ...])
(count s) ;;=> 6
(s/explain ::ba-decline (take 3 s)) ;;=> Success!
(s/explain ::ba-decline (drop 3 s)) ;;=> Success!
(s/explain (s/cat :one ::ba-decline :two ::ba-decline) s)
;; fails, claiming that the first element of s does not satify: (or (nil? %) (sequential? %)) in: [0] at: [:one]


(this works with spec1)


Am I missing something obvious about combining regex specs?


The ::ba-decline spec is an s/cat of three items.


I'll see if I can create a minimal example that fails, based on this (unfortunately there are a lot of complex specs behind this).



(s/def ::x string?)
(s/def ::y int?)
(s/def ::z keyword?)
(s/def ::a (s/keys :req-un [::x]))
(s/def ::b (s/keys :req-un [::y]))
(s/def ::c (s/keys :req-un [::z]))
(s/def ::abc (s/cat :a ::a :b ::b :c ::c))
(def a {:x "x"})
(def b {:y 42})
(def c {:z :bar})
(s/explain ::abc [a b c])
(s/explain (s/cat :one ::abc :two ::abc) [a b c a b c])
works on spec1, fails on spec2


on spec2 {:x "x"} - failed: (or (nil? %) (sequential? %)) in: [0] at: [:one]

Alex Miller (Clojure team)23:02:42

user=> (s/explain (s/cat :one ::abc :two ::abc) [[a b c] [a b c]])
certainly is suspicious :)


It's almost like regex specs don't unroll anymore! :rolling_on_the_floor_laughing:

Alex Miller (Clojure team)23:02:43

I may have actually introduced that by introducing the delayed resolution of aliased specs

Alex Miller (Clojure team)23:02:07

basically regex specs in the registry are shielded by the keyword (which is not a regex spec), so the code doesn’t believe they can be combined

Alex Miller (Clojure team)23:02:05

so this may fight with the last changes - I can’t remember now if that was from forward references or from something about gens?


This was broken before you fixed either of those I believe. Certainly broken before the gensub fix.

Alex Miller (Clojure team)23:02:30

well good to know then :)


Although, with a quick clj -Sdeps ... it's enough to test that repro case against any version of spec2 🙂

bananadance 5
Alex Miller (Clojure team)22:02:42

I’ll take a look, seems buggy to me

Alex Miller (Clojure team)22:02:10

There is a lot gnarly code in that form/object transition. I could easily have broken something subtle


I was lucky that the first simple repro I tried still broke 🙂

Alex Miller (Clojure team)22:02:13

Hey, that’s a good sign


At this point, it really is a pretty minimal set of changes in our code to go from spec1 to spec2. It's frustrating that we can no longer use comp and partial to construct predicates and have to resort to #(..) or (fn [x] ..) but, fortunately, that didn't affect much code.


We have a few places we're having to use s/spec* now so the "helper macros" mentioned in your latest journal will help clean that up when they drop in GitHub.

Alex Miller (Clojure team)22:02:10

yeah, that has further solidified today and I think will be very useful


I still have at least 3 bugs with spec alpha 2 (see issue link above)


Interesting. I never knew you could define a spec to nil to make it go away...


It’s a fairly recent addition.


Make that 2. The (s/def spec nil) was a mistake on my part, I had to call unstrument first (which failed because ::s/invalid is not a valid any? which I ran into)


undefining still works:

$ clj -A:test
Clojure 1.10.0
user=>  (require '[clojure.spec-alpha2 :as s])
user=> (require '[clojure.spec-alpha2.test :as stest])
user=> (defn foo [x] x)
user=> (s/fdef foo :args (s/cat :x number?) :ret number?)
user=> (stest/instrument `foo)
user=> (foo "a")
Execution error - invalid arguments to user/foo at (test.clj:129).
"a" - failed: number? at: [:x]
user=> (stest/unstrument)
user=> (s/def foo nil)
user=> (stest/instrument `foo)