Fork me on GitHub
#clojure-spec
<
2016-07-14
>
mjmeintjes04:07:12

Hi. Is there a way to use spec to generate maps with "dependent" properties. For example, suppose my map spec requires than both :a and šŸ˜› contain strings that have to be the same length?

mjmeintjes04:07:27

That should be - Is there a way to use spec to generate maps with "dependent" properties. For example, suppose my map spec requires than both :a and :b contain strings that have to be the same length?

seancorfield04:07:52

@mjmeintjes: Well, you can use s/and to restrict what a spec generates but that might not be the easiest way to make the generator work...

seancorfield05:07:04

Hmm, perhaps it's OK after all:

boot.user> (require '[clojure.spec :as s])
nil
boot.user> (s/def ::a string?)
:boot.user/a
boot.user> (s/def ::b string?)
:boot.user/b
boot.user> (s/def ::foo (s/and (s/keys :req [::a ::b]) #(= (count (::a %)) (count (::b %)))))
:boot.user/foo
boot.user> (s/exercise ::foo)
([#:boot.user{:a "", :b ""} #:boot.user{:a "", :b ""}] [#:boot.user{:a "z", :b "S"} #:boot.user{:a "z", :b "S"}] [#:boot.user{:a "GF", :b "y8"} #:boot.user{:a "GF", :b "y8"}] [#:boot.user{:a "c5kf9D7nt88PhP2zRiIj", :b "Ax9Ua1vd561LvuWZ0o5r"} #:boot.user{:a "c5kf9D7nt88PhP2zRiIj", :b "Ax9Ua1vd561LvuWZ0o5r"}] [#:boot.user{:a "", :b ""} #:boot.user{:a "", :b ""}] [#:boot.user{:a "yaLME3MI4uSh0", :b "FIxs99gp43jSe"} #:boot.user{:a "yaLME3MI4uSh0", :b "FIxs99gp43jSe"}] [#:boot.user{:a "9", :b "3"} #:boot.user{:a "9", :b "3"}] [#:boot.user{:a "f7nOvuwZ30U000f", :b "3enZpUsZXP9ZVX1"} #:boot.user{:a "f7nOvuwZ30U000f", :b "3enZpUsZXP9ZVX1"}] [#:boot.user{:a "8aDmY08S8Q", :b "rHFcc5rAN9"} #:boot.user{:a "8aDmY08S8Q", :b "rHFcc5rAN9"}] [#:boot.user{:a "Ds8zm6", :b "yM0N6p"} #:boot.user{:a "Ds8zm6", :b "yM0N6p"}])

mjmeintjes06:07:12

@seancorfield: Great, thanks! Looks promising, I'll investigate further.

glv14:07:52

After converting some property-based tests to use specā€™s generators, I noticed that some of the tests became much slower. Investigation reveals that the growth characteristics of specā€™s generators can be quite different from those of test.check. Hereā€™s an example:

glv14:07:19

In most cases I doubt the difference would be very noticeable, but in my case two such generated integer values were being used as the dimensions of a two-dimensional matrix structure, so the size really blew up quickly.

glv14:07:03

I can see a rationale for making the growth a little steeper than the test.check version, but this seems a bit severe. šŸ™‚

glv17:07:30

Especially since the default for :num-tests is 1000. šŸ˜®

seancorfield17:07:07

I would say, in this case where the amount of data you test is N-squared based on random generated values, you probably want a custom generator that heavily restricts those dimension values?

seancorfield17:07:38

How big, realistically, is a matrix you would be handling?

glv17:07:10

Oh, sure ā€¦ Iā€™ve done exactly that, now. Just wondering whether this is an appropriate default.

glv17:07:42

Given the actual behavior over 1000 iterations, youā€™d run into problems even if the amount of data was linear wrt the integer value.

glv17:07:06

And given that the visible symptom is just ā€œmy test run seems to just stallā€ itā€™s a bit confusing.

glv17:07:16

(Oh, and ā€¦ my first attempt at constraining the generator was just to slap a #(< % 25) predicate on there, and then I got sporadic "Couldn't satisfy such-that predicate after 100 triesā€ failures. Which was easy enough to fix, but still leads me to think that the generator growth is just too fast.)

Tim20:07:48

what is the justification of having spec in separate namespaces than the actual functions?

kendall.buchanan21:07:42

What happened to instrument-ns in alpha10? Not possible anymore?

glv21:07:02

folded into instrument. (instrument ā€˜my.namespace)

glv21:07:40

Ah, Iā€™ve figured out whatā€™s going on with the growth rate of (s/gen pos-int?) mentioned above: some of the generators for built-in predicates use test.check functions that ignore the size guidance. This means (I think) that they wonā€™t shrink properly when an error is found: https://github.com/clojure/clojure/blob/d920ada9fab7e9b8342d28d8295a600a814c1d8a/src/clj/clojure/spec/gen.clj#L128-L185

glv22:07:55

@alexmiller: Iā€™d love to hear your thinking on this when you get a chance. Discussion starts at https://clojurians.slack.com/archives/clojure-spec/p1468507432002694

ghadi22:07:13

I think he'll be back tomorrow Glenn

glv22:07:24

OK, thanks!