Fork me on GitHub
#clojure-spec
<
2017-10-07
>
ajs07:10:48

Since instrument does not check the return value, it would seem to me that a :post condition is still quite useful.

mpenet08:10:31

I tend to use s/assert instead nowadays

ajs09:10:33

with :post at least, you don’t have to let your fn’s return value so you can assert it before you return it

ajs09:10:55

does s/valid? work on all components of fspec?

guy09:10:30

what do you mean

guy09:10:30

oh right got you

ajs09:10:51

i know that instrument only looks at args, but i haven’t tried out how valid? works on it. will try that when i get home.

ajs09:10:55

would be cool if that worked

guy09:10:15

well instrument works on the return value too ?

guy09:10:26

thats why u have :args, :ret :fn

ajs11:10:24

@guy no it doesn't. Are you sure? Check the docs. Only args are supported for instrument, though you can specify ret and fn for other purposes.

ajs12:10:29

"Note that the :ret and :fn specs are not checked with instrumentation..."

jaymartin12:10:37

@ajs Where exactly are you seeing that note, as I can’t find it.

ajs12:10:23

The spec guide itself, in instrument section. Why do you think libraries like Orchestra exist?

jaymartin12:10:12

Silly me, I was looking in the doc string for instrument.

jaymartin12:10:46

So then, is fdef orthogonal in some way. Its doc string says: “Once registered, function specs are included in doc, checked by instrument, tested by the runner clojure.spec.test/run-tests, and (if a macro) used to explain errors during macroexpansion.”

jaymartin12:10:45

I think I need to start over at the spec guide itself and re-read.

ajs12:10:48

The are tested by instrument for :args only I think

ajs14:10:55

Other than tests, I gather there's really no way to perform validation on the entirety of a function's signature, including its return value, and also validating that the entire fn received in a higher order function, is what is expected, is that right?

Alex Miller (Clojure team)15:10:33

stest/check is the only thing in spec that validates :ret and :fn specs

Alex Miller (Clojure team)15:10:18

I’m not sure I fully understand the question re hof

ajs16:10:28

That answers it!

taylor13:10:02

I’m trying to write a spec for a collection where I need the first item to conform to another spec. s/cat works great, but when I fdef and check an unary function of that collection it looks like test.check is applying the collection to the function, and so I get arity exceptions. Should I change the function to take varargs?

gfredericks13:10:46

are you using s/cat to express the whole arglist or just the first arg?

gfredericks13:10:04

I think to use a regex for a single arg you'll need to wrap in s/spec, maybe that's what you're missing

gfredericks13:10:16

(s/cat :first-arg (s/spec (s/cat ...))) something like that

taylor13:10:42

yeah, my :args is (s/cat :clause (s/spec ::group))

gfredericks13:10:11

I don't know then. You certainly should be able to spec that.

taylor13:10:17

actually it does work when I wrap with s/spec, but I think I need to limit the test cases because it’s running forever

taylor13:10:09

the spec is recursive and I guess is getting really complex samples

gfredericks13:10:23

yeah 😞 the Big Problem of spec/test.check

taylor13:10:21

well the good news is this is a toy problem 🙂

ajs14:10:55
replied to a thread:correct

Other than tests, I gather there's really no way to perform validation on the entirety of a function's signature, including its return value, and also validating that the entire fn received in a higher order function, is what is expected, is that right?

taylor14:10:11

(binding [clojure.spec.alpha/*recursion-limit* 1]
  (stest/check `clause-str {:num-tests 1}))

taylor14:10:25

is ☝️ what recursion limit is there for?

taylor14:10:46

it runs pretty quickly like that

gfredericks14:10:12

I think so. what's it default to?

tbaldridge14:10:16

The depth of spec checking is somewhat limited by the JVM stack size, that keeps the generators from blowing the stack. Without it, you’d get a stack overflow from almost any recursive structure.

gfredericks14:10:33

@tbaldridge you're saying *recursion-limit* refers to checking rather than generation?

tbaldridge14:10:05

It only refers to generation. Checking is assumed to be bounded by the depth of the input

gfredericks14:10:05

okay. I think there could be a more automatic approach to handling the recursion, but I'm not sure.

gfredericks14:10:47

I have to come up with something for the vanilla test.check collection generators, so whatever works there might apply to how spec assembles generators

tbaldridge14:10:13

There probably could be. That dynamic var got added in one of the pre-alpha builds when I tried to build a recursive spec and it would stack overflow on the first structure generated.

tbaldridge14:10:01

Checking is fine since that's GIGO, so it's on the user not to check data that's millions of levels deep.

tbaldridge14:10:42

@gfredericks any insight in the past year about shrinking recursive generators?

tbaldridge14:10:49

They currently shrink by width (and a b) -> (and a), but not by depth: (and (and (and a))) -> (and a). I know we discussed this once, not sure if anything has changed in the past year

gfredericks14:10:09

I don't think I have any thoughts that I didn't put on the ticket

taylor14:10:59

Ha. This is exactly the type of structure I’m generating too

gfredericks15:10:10

@U3DAE8HMG important to note here that spec doesn't use recursive-gen

gfredericks15:10:15

But spec's approach has the same problem, but even worse

gfredericks14:10:43

the unfortunate part is that after generating a collection, test.check can't (in general) tell what parts the children are

gfredericks14:10:47

and you'd need their shrink-trees in any case, not just the data

gfredericks14:10:54

I was thinking that there's an unsound approach where you wrap the child generator in an observer that keeps track of how it was called and use that to add shrinking info I thought it was unsound because you can't tell just because the generator was called, that the result actually appears in the final structure but I just realized that that probably doesn't matter. anything generated by the child generator should be a valid value from the final generator, so even if it doesn't appear in the actual data, it's not an invalid thing to shrink to in the strict sense

gfredericks14:10:36

so now the worst thing about this approach is that it's a bit messy

gfredericks14:10:04

but I think everything still ends up being deterministic

gfredericks14:10:56

I'll go comment on the ticket. I don't have time to work on it until at least thursday

gfredericks15:10:20

Well maybe not worse....

tbaldridge15:10:03

ah right, I forgot about that. Spec's stack overflow happened during the creation of the generator

gfredericks15:10:05

the thing about spec's approach is that it's committing to a particular depth in the generator rather than describing the recursion the way the spec itself does

gfredericks15:10:22

it might be making other commitments in the process, I'm not sure

gfredericks15:10:42

I'm not sure this is a significant problem, it just complicates things