Fork me on GitHub
#clojure-spec
<
2020-01-03
>
Eddie03:01:44

@seancorfield I spent some time today with spec 2. It seems like it's design goals are exactly what I need. I attempted to migrate and it was pretty rough (not complaining, I totally understand that it is still in development and also a new major version so I expected many breaking changes). I am not sure if we will be jumping on board with spec 2 yet, but thank you for the pointer!

Eddie03:01:18

There are a few things that we are doing in spec 1 that I cannot figure out how to recreate in spec 2, even though it smells like it should be possible. For example, I would like to implement a custom generator that simply pulls a random element from a set. I can get this to work if the set satisfies (every? constant-val? ...) but otherwise, I cannot.

Alex Miller (Clojure team)03:01:28

are you using a set spec?

Alex Miller (Clojure team)03:01:16

user=> (s/def ::s #{1 2 3})
:user/s
user=> (gen/sample (s/gen ::s))
(2 1 3 2 2 1 1 1 2 2)

Alex Miller (Clojure team)03:01:44

if you're trying to do this outside s/def (which has some magic), you can do something like

user=> (gen/sample (s/gen (s/resolve-spec #{1 2 3})))
(1 2 1 1 3 1 3 3 1 1)

Alex Miller (Clojure team)04:01:20

one of the caveats you might be seeing is that set specs are constrained to constant values only which is part of the new symbolic spec direction

Alex Miller (Clojure team)04:01:52

there are a couple of options but you can just use the built-in generators directly if you have something else

Eddie17:01:11

Thank you! gen/elements is exactly what I was looking for. However I am running into some strange behavior on the with-gen .

user=> (s/with-gen (s/spec int?)
                   (fn [] (gen/elements [-1 0 1])))
Execution error (IllegalArgumentException) at clojure.alpha.spec.protocols/eval190$fn$G (protocols.clj:11).
No implementation of method: :with-gen* of protocol: #'clojure.alpha.spec.protocols/Spec found for class: clojure.lang.PersistentList

user=> (s/exercise (s/with-gen int? (fn [] (gen/elements [-1 0 1])))
            10)
([-1 -1] [0 0] [1 1] [-1 -1] [-1 -1] [-1 -1] [0 0] [1 1] [-1 -1] [1 1])
Neither of those seem right to me. Am I missing a change from Spec 1?

Alex Miller (Clojure team)17:01:50

yeah, seems fishy. I'd expect the first one to work

Alex Miller (Clojure team)04:01:02

user=> (def a 1) (def b 2)
#'user/a
#'user/b
user=> (gen/sample (gen/elements [a b]))
(1 2 2 2 1 2 2 2 2 2)

A.J. Gardner16:01:52

hello! it seems like @rafael and I ran into the same issue. I posted about it in the google group: https://groups.google.com/d/topic/clojure/rcuWmqyGWzs/discussion my specs:

(s/def ::id int?)
(s/def ::tag-id ::id)
(s/def ::child-tag ::tag-id)
(s/conform ::child-tag 22)
;; 22
(s/conform ::child-tag "a")
;; :clojure.alpha.spec/invalid
(s/conform (s/schema [::child-tag]) {::child-tag 22})
;; Execution error (IllegalArgumentException) at clojure.alpha.spec.protocols/eval1458$fn$G (protocols.clj:11).
;; No implementation of method: :conform* of protocol: #'clojure.alpha.spec.protocols/Spec found for class: clojure.lang.Keyword
(s/conform (s/schema [::tag-id]) {::tag-id 22})
;; Execution error (IllegalArgumentException) at clojure.alpha.spec.protocols/eval1458$fn$G (protocols.clj:11).
;; No implementation of method: :conform* of protocol: #'clojure.alpha.spec.protocols/Spec found for class: clojure.lang.Keyword
(s/conform (s/schema [::id]) {::id 22})
;; #:foo{:id 22}

A.J. Gardner16:01:14

and the stack trace, just in case that’s useful:

(clojure.repl/pst)
IllegalArgumentException No implementation of method: :conform* of protocol: #'clojure.alpha.spec.protocols/Spec found for class: clojure.lang.Keyword
	clojure.core/-cache-protocol-fn (core_deftype.clj:583)
	clojure.core/-cache-protocol-fn (core_deftype.clj:575)
	clojure.alpha.spec.protocols/eval1458/fn--1556/G--1439--1567 (protocols.clj:11)
	clojure.alpha.spec.impl/schema-impl/reify--2753 (impl.clj:435)
	clojure.alpha.spec/conform (spec.clj:245)
	clojure.alpha.spec/conform (spec.clj:237)
	clojure.alpha.spec/conform (spec.clj:241)
	clojure.alpha.spec/conform (spec.clj:237)
	foo/eval6028 (form-init13722384443750232197.clj:1)
	foo/eval6028 (form-init13722384443750232197.clj:1)
	clojure.lang.Compiler.eval (Compiler.java:7177)
	clojure.lang.Compiler.eval (Compiler.java:7132)

Alex Miller (Clojure team)16:01:40

yeah, this is just a bug in spec