Fork me on GitHub
#clojure-spec
<
2017-11-22
>
qqq03:11:15

The question is NOT "what is wrong with this code." The question is "how do I get a more useful error msg"

(s/def ::ys number?)
(s/def ::xs number?)
(s/def ::data any?) 
(defn mat-of [ys xs q? data]
  (assert (vector? data))
  (assert (= (count data) ys))
  (doseq [y (range  ys)]
    (assert (= (count (get data y)) xs)
            (str "count of row " y " is " (count (get data y)) " not " xs))))
(s/def ::keyPad (s/and (s/keys :req-un [::xs ::ys ::data])
                       (fn [obj]
                         (mat-of (:ys obj) (:xs obj) any? (:data obj)))))
(s/explain ::keyPad
          {:ys   3
           :xs   3
           :data [[7 8 9]
                  [4 5 6]
                  [1 2 3]]})



returns false. I expect it to return true. It appears to be eating the assertion error. Is there a way to get a more helpful msg on why it's failing the predicate ?

qqq03:11:14

reframing question: when using predicates with clojure spec, is there a way, instead of just returning true/false, also return a error msg on false ?

qqq04:11:31

is this a short coming of current spec design, or is this because I'm mis using spec and should be using spec primitives as much as possible instead

seancorfield04:11:40

One thing I've found helpful @qqq is to break predicates down into smaller components and give them names. That way the explain refers to the named predicates. In your case, I'd write data-is-vector?, data-has-ys-rows?, and data-has-xs-cols? and have those accept the whole hash map and return true/false. Then you'd have (s/and (s/keys :req-un [::xs ::ys ::data]) data-is-vector? data-has-ys-rows? data-has-xs-cols?) and I believe you'll get better error messages -- without using assert.

seancorfield04:11:53

The other thing we do is take the explain-data and parse it so we can map symbols and forms to English error messages (well, actually to i18n keys so that we can produce error messages in any language!).

hkjels08:11:41

So, I’ve written quite a lot of ui-components where I use spec for various things. Mostly checking that parameters used with the components are valid. I’ve come to a stage where I’m doing performance-testing and it seems that spec is sucking the life out of this project. Is it just a bad idea to use spec for such a task?

andre.stylianos09:11:27

I believe the encouraged way is to use spec for production code only at the boundaries where you receive data from sources you don't control. Beyond that, the validation that you do for internal code should be used only for development.

hkjels09:11:12

OK.. Then I’ll have to use something like spec/nonconform all over the place in dev then

hkjels09:11:59

I guess it makes sense to not have it on in production

ikitommi10:11:09

@hkjels just turn off the validation for real app? e.g. instrument the component functions for dev. Or use assert and disable that for prod. Haven’t used spec for ui but did that at some point with Schema. WIth it, you can disable function validations and the schematized defs and fns will not emit any code related to Schemas => no penalty.

hkjels11:11:32

When I disabled validation, it definitely got a performance boost

hkjels11:11:24

conform is still one of the heavier tasks in the performance-tab og chrome, but it’s also doing quite some work, so that makes sense I guess

hkjels11:11:11

I have to do some more testing, but this might do

guy12:11:42

When you fdef a function with no args, do you just omit the :args key?

Alex Miller (Clojure team)13:11:49

No, you should use (s/cat) to validate 0 arity

Alex Miller (Clojure team)13:11:46

Also, you should be suspicious of 0 arity functions. Either they have side effects (and maybe shouldn’t be spec’ed) or you can just use a def instead.

otfrom13:11:25

@seancorfield and @alexmiller are there any good examples out there of using relatively complex :fn functions in fdefs? I saw that and hints above and wonder if that is the best way to go to figure out which bit of the property is being violated

Alex Miller (Clojure team)13:11:22

I’ve written some here and there but not sure if in anything public. If they get too complicated, then you have to question whether that’s the best way to test. Sometimes straight test.check is better

otfrom13:11:54

cool, that makes sense

qqq17:11:27

I realize this is a bad idea in most cases, but is it possible to say: (s/maps ... key :buttonContainer satisfies spec ::container) ?

Alex Miller (Clojure team)18:11:06

Don’t understand the question

bronsa18:11:35

are you looking for :req-un?

Alex Miller (Clojure team)20:11:57

FYI, I’ve been working on fix the auto doc junk for Clojure and contrib and the docs have been updated for Clojure, spec.alpha, and links in the spec guide

seancorfield21:11:30

@alexmiller That's great to hear -- thank you! Is there anything I can do to help get http://clojure.github.io/java.jdbc/ updated too?

Alex Miller (Clojure team)21:11:23

nope. I can try to run it manually though…

Alex Miller (Clojure team)21:11:29

@seancorfield I’m not sure if you had specs in those vars in the prior docs, but they are showing up now

seancorfield21:11:18

Oh cool! No, I don't think the specs were showing up before.

seancorfield21:11:25

That is very nice! Thank you!