Fork me on GitHub

@alexmiller Want me to go back to my spec2 branch and start testing our code against this again? Happy to do so starting Monday if you think this should have parity with current spec?


(originally posted in #announcements by accident!)


I see that s/keys is still part of the api in spec2. I'm a bit surprised given RH's talk on how he wants to separate that out into s/schema and s/select. Are these going to be added in addition to s/keys then or is s/keysgoing away in favor of them in the next iteration? If they'll all exist together, will it ever make sense to use s/keys over s/schema/`s/select`?


@madstap That's a bit unfair -- the refactor to spec2 started before Conj.


The shape/required stuff is further down the pike.


The work in spec2 is groundwork to prepare for that.


Sure, my question is more about the direction spec will take. Is s/keys "living on borrowed time" so to speak?


Yeah, I'd say s/keys is living on borrowed time. Spec is still alpha so it's subject to API breakage.


Given the namespace changes, you can have both libraries loaded and both types of specs defined while you transition.


That's the important part of namespace changes.


Yeah, just like RH talked about in his penultimate(?) keynote. Pretty cool to see how that approach works out in practice.


This is why next.jdbc will be a new namespace at least and a new artifact more likely 🙂

Alex Miller (Clojure team)04:01:15

Unknown yet on s/keys. We haven’t started any of the work yet for the stuff rich talked about at conj

Alex Miller (Clojure team)04:01:55

Look, people complain when we work in a private repo, then drop something at the end. We’re trying to do something different here which means you get to see all the steps along the way, so things will be changing over a probably months

Alex Miller (Clojure team)04:01:55

Some of it will be experimental


I'm not complaining, I hope it didn't come across that way


I love that you're dropping stuff we can test against.

Alex Miller (Clojure team)04:01:41

Just saying, don’t expect it all at once


I don't much care which way you're going with the API -- we'll follow, regardless, even if we have to keep changing code 🙂


(we're living on the bleeding edge for a reason -- it gives us an edge!)


And this iteration solves one of the big pain points which were programmable specs


One observation about that though: The way spec op macros are implemented now breaks clojure.walk/macroexpand-all, which will stack overflow if the form contains any spec macros.


That's good feedback for the development of spec2. Last time I tried our code against spec2, a lot of stuff broke. I'll be trying it again on Monday when I get back to work. Breakage is to be expected in prerelease work and if folks pitch in and try it, the core team get more feedback which is helpful!


I have this spec in spec1:

#?(:clj (s/def ::java-map
          (s/with-gen #(instance? java.util.Map %)
            (fn [] (gen/fmap #(java.util.HashMap. %)
                             (s/gen ::map))))))
On spec2 I get:
Caused by: java.lang.IllegalArgumentException: no conversion to symbol
	at clojure.core$symbol.invokeStatic(core.clj:596)
	at clojure.core$symbol.invoke(core.clj:589)
	at clojure.spec_alpha2$explicate_1$fn__904.invoke(spec_alpha2.clj:314)
I have to look into this more, I just briefly tried it

Alex Miller (Clojure team)14:01:39

The key thing is that specs have to start off as forms, not function objects. So here the anonymous function is getting evaluated too early and I suspect you need to quote the (fn ... ). That may be fixable though in spec since I turned with-gen into a macro. I’ll take a look when I’m at a computer.


Quoting the fn didn’t help


same with:

#?(:clj (s/def ::char-sequence
            #(instance? java.lang.CharSequence %)
            (fn []
              (gen/one-of (map #(gen/fmap %
                                          (s/gen ::string))
                               [#(StringBuffer. %)
                                #(StringBuilder. %)
                                #(java.nio.CharBuffer/wrap %)
                                #(String. %)]))))))


This spec breaks:

(defn seqable-of
  "every is not designed to deal with seqable?, this is a way around it"
  (s/with-gen (s/and seqable?
                     (s/or :empty empty?
                           :seq (s/and (s/conformer seq)
                                       (s/every spec))))
    #(s/gen (s/nilable (s/every spec :kind coll?)))))

(s/def ::seqable-of-map-entry (seqable-of ::map-entry))
with the message:
Caused by: java.lang.IllegalArgumentException: No method in multimethod 'create-spec' for dispatch value: speculative.specs/seqable-of


I tried to fix it like this: But I get:

user=> (s/valid? ::ss/seqable-of-map-entry {:a 1 :b 2})
Execution error (IllegalArgumentException) at clojure.spec-alpha2/pred-impl (spec_alpha2.clj:132).
I’ll leave it at this for now. Broken code is indicated with FIXME’s here:


Hello, I have a case where having the keys of a map spec forced to be namespaced qualified, leads to a case like this:

(defn do-this [args]
  ;; ...
  {:foo :bar
   :resource {:key-a 1}})

(s/def ::foo keyword?)
(s/def ::key-a int?)
(s/def ::resource (s/keys req-un [::key-a]))
(s/fdef do-this
  :ret (s/keys :req-un [::foo ::resource]))

(defn do-that [args]
  ;; ...
  {:foo :bar
   :resource {:key-b "plop"}})

(s/def ::key-b string?)
;; (s/def ::resource (s/keys req-un [::key-b])) <-- problem here: the spec is being redefined
(s/fdef do-this
  :ret (s/keys :req-un [::foo ::resource]))
Here I would like to have to functions in the same namespace that return two different "partial views" of a resource along with other information in a map. It seems that I can't due to the fact that two pieces of information are glued together: the unqualified key and the spec. I feel like I miss kind of a scoped spec declaration or a function like this : (s/key :resource <spec>) that I can embed in the declaration: (s/keys :req-un [(s/key :resource <spec>) ::foo]). But I feel also that I am maybe misusing the library. Has someone bumped into this problem already? Thanks


@dam since you use :req-un in all 3 s/keys, you can pick another namespace for second ::resource:

(s/def :baz/resource  (s/keys req-un [::key-a]))
(s/def :quux/resource (s/keys req-un [::key-b]))
(s/fdef do-this :ret (s/keys :req-un [::foo :baz/resource]))
(s/fdef do-that :ret (s/keys :req-un [::foo :quux/resource]))