Fork me on GitHub
#clojure-spec
<
2016-08-11
>
rickmoynihan12:08:56

@alexmiller: super useful screencast thanks again! One thing I've not quite grokked yet is the full relationship between spec and test.check... I understand it's a dev time dependency for the generators... but should you ever be using raw clojure.test generator functions? Or should you use spec as a wrapper or use both?

rickmoynihan12:08:46

I noticed that spec lazy-loaded test.check underneath too... not sure what the purpose of that is

Alex Miller (Clojure team)13:08:34

spec.gen relies on test.check and exposes most of its generator functions

Alex Miller (Clojure team)13:08:31

This anything that uses generators will require a dependency on test.check (we expect that to primarily be a test time dependency)

Alex Miller (Clojure team)13:08:42

spec.gen wraps those functions to dynamically load them though, allowing you to build generators without incurring a load-time dependency on test.check

Alex Miller (Clojure team)13:08:41

So you should always prefer using spec.gen as that lets you use specs in other ways without incurring that dependency

Alex Miller (Clojure team)13:08:32

Maybe this itself would be a good blog topic :)

borkdude14:08:55

What is the reason :ret is not checked by t/instrument?

gfredericks15:08:10

man we need some kind of canonical link for that question

glv15:08:59

t/instrument is designed to help you ensure that you’re calling functions correctly, according to spec. Checking that functions (yours or someone else’s) are implemented correctly is a different job, handled by st/check.

minimal15:08:57

Could pin that ^

andrewhr16:08:00

not sure how well this will play with our history constraints

gfredericks16:08:57

amend it with "please re-say&pin this message each morning"

minimal16:08:13

I see plenty of old things pinned on other channels

seancorfield16:08:19

@rickmoynihan: we use test.chuck for additional generators and we've taken the same approach of loading it dynamically as a test-only dependency /cc @alexmiller

glv16:08:38

Yeah, I think pinned stuff sticks around.

gfredericks16:08:00

@seancorfield: you just generated a bunch of lazy vars?

andrewhr16:08:13

theres is some documentation update planned regarding this issue @alexmiller? Something the community could help you with? Sorry if the docs were already amended with this point, I didn't re-read them lately

rickmoynihan16:08:39

alexmiller: thanks for the enlightening answer... And I think it would be another great blog topic 🙂

rickmoynihan16:08:05

seancorfield: yeah test.chuck is awesome (thanks gfredericks btw) how do you load it as a test time dependency only? Do you mean just through a dev/test profile? Or do you mean you're reusing core.specs lazy loading things somehow.

ghadi16:08:59

re :ret it in fact says it in the guide -- I think people have a false expectation of the tool to behave in a certain symmetric (for lack of a better term) way. But the real distinction is about development (`instrument` - :ret) vs test (`check` + :ret) time. As you know dev time vs test time is a little blurrier in a REPL.

ghadi16:08:49

if you think of it (and teach it to people!) in terms of that distinction, it becomes intuitive

Alex Miller (Clojure team)16:08:36

@andrewhr sorry, what issue are you referring to? (several things in this channel)

Alex Miller (Clojure team)16:08:35

the guide is updated with each alpha so should be in sync

Alex Miller (Clojure team)16:08:11

guide discusses it, docstrings I think are up to date. where else should it be?

andrewhr16:08:17

great! It's a pretty common question and we've not sure if the docs were up to date.. sorry for my laziness in not checking there before asking you

Alex Miller (Clojure team)16:08:18

I started working on a reference page for spec which will be kind of somewhere between the docstrings and the guide, eventually I’ll get around to finishing that

andrewhr16:08:27

looks promising! thanks for working on that 🙂

seancorfield16:08:07

@rickmoynihan: we wrap stuff we need to use in a function like this

(defn fn-string-from-regex
  "Return a function that produces a generator for the given
  regular expression string."
  [regex]
  (fn []
    (require '[com.gfredericks.test.chuck.generators :as xgen])
    (let [string-from-regex (resolve 'xgen/string-from-regex)]
      (string-from-regex regex))))
/cc @gfredericks

seancorfield16:08:01

In my build.boot file I have

(deftask testing-context
  "Provide main testing context."
  []
  (merge-env! :dependencies '[[com.gfredericks/test.chuck "0.2.7" :scope "test"
                               :exclusions [*/*]]
                              [javax.servlet/servlet-api "2.5" :scope "test"]
                              [org.clojure/test.check "0.9.0" :scope "test"]])
  identity)

seancorfield16:08:12

that task is chained in ahead of any testing tasks, to make the libraries available, but scoped so they don’t end up in artifacts (in case a build test accidentally got chained in with a testing task).

borkdude18:08:17

how do you say in spec: map of keywords and arbitrary values

borkdude18:08:38

(s/map-of keyword? (constantly true))?

borkdude18:08:57

sorry if I'm asking the obvious, but why are there both or and alt? alt is used in sequences, but why isn't or used there?

Alex Miller (Clojure team)18:08:40

this is covered briefly in the guide btw

Alex Miller (Clojure team)18:08:03

alt describes alternatives that are in the context of a sequence

Alex Miller (Clojure team)18:08:46

a spec with alt can thus be reused in different regex op contexts

Alex Miller (Clojure team)18:08:02

whereas or represents a spec for a single value

Alex Miller (Clojure team)18:08:39

there are situations where either would give you the same result but then there are cases where they would not

Alex Miller (Clojure team)18:08:25

it’s better to start from the direction of what you’re spec’ing - if it is syntax in a sequential context, then use alt, otherwise use or

Alex Miller (Clojure team)18:08:57

(s/conform (s/* (s/alt :n number? :k keyword?)) [5 :a 10 :b 20 :c])

Alex Miller (Clojure team)18:08:25

you are describing the structure / syntax of a sequential structure there

Alex Miller (Clojure team)18:08:43

(note that you can’t use s/or here)

borkdude18:08:16

@alexmiller: thanks for explaining - I tried to find it in the guide, but couldn't understand it as clear as you explain it now

Alex Miller (Clojure team)18:08:27

(s/conform (s/or :n number? :k keyword?) 100)

Alex Miller (Clojure team)18:08:40

here you’re describing a single value - use s/or

donaldball18:08:33

Is there any reason to avoid using (s/tuple …) for the :args value of s/fdef?

borkdude18:08:54

repl=> (s/conform (s/* (s/alt :n number? :k keyword?)) [5 :a 10 :b 20 :c])
[[:n 5] [:k :a] [:n 10] [:k :b] [:n 20] [:k :c]]
repl=> (s/conform (s/* (s/or :n number? :k keyword?)) [5 :a 10 :b 20 :c])
[[:n 5] [:k :a] [:n 10] [:k :b] [:n 20] [:k :c]]

borkdude18:08:13

both just work

Alex Miller (Clojure team)18:08:22

but regex forms like cat are preferred

Alex Miller (Clojure team)18:08:45

b/c the conformed result will tag the arguments (which tuples don’t)

Alex Miller (Clojure team)18:08:07

again, this is syntax (the syntax of a function) so that’s a better match

borkdude18:08:10

hmm:

repl=> (s/conform (s/* (s/or :n (s/* number?) :s (s/* string?))) [[1 2 3]])
[[:n [1 2 3]]]
repl=> (s/conform (s/* (s/alt :n (s/* number?) :s (s/* string?))) [[1 2 3]])

StackOverflowError   clojure.core/implements? (core_deftype.clj:539)

borkdude18:08:48

did I break something? 😉

Alex Miller (Clojure team)18:08:49

I can’t spot anything immediately that would make that result acceptable :)

Alex Miller (Clojure team)18:08:23

I would not expect that value to actually satisfy that spec though

Alex Miller (Clojure team)18:08:45

you are describing sequences like [1 2 3 “a” “b” 4 5 6 “d” “e”]

borkdude18:08:18

yeah, weird right?

Alex Miller (Clojure team)18:08:19

whereas the first s/or spec is for sequences like [[1 2 3] [“a” “b”] [4 5 6] [“d” “e”]]

Alex Miller (Clojure team)18:08:40

if you can file a jira, that would be useful

borkdude18:08:41

ah, then I found a good example to explain the difference?

Alex Miller (Clojure team)18:08:36

really, I don’t think I would use s/or to describe either of those two kinds of inputs

Alex Miller (Clojure team)18:08:09

well, it might make sense, it really depends on semantics

borkdude18:08:29

How would you describe

[[1 2 3] [“a” “b”] [4 5 6] [“d” “e”]]
?

borkdude18:08:32

Jira ticket coming btw

Alex Miller (Clojure team)18:08:01

(s/conform (s/* (s/spec (s/alt :n (s/* number?) :s (s/* string?)))) [[1 2 3] ["a" "b"] [4 5 6]])

Alex Miller (Clojure team)18:08:10

or you could do (s/conform (s/* (s/or :n (s/coll-of number?) :s (s/coll-of string?))) [[1 2 3] ["a" "b"] [4 5 6]])

borkdude18:08:48

I would choose the second probably too

borkdude18:08:09

(s/conform (s/* (s/spec (s/alt :n (s/* number?) :s (s/* string?)))) [[1 2 3]])
;;=> [[:n [1 2 3]]]

borkdude18:08:45

@alexmiller: so was the bug that I missed the surrounding s/spec?

borkdude18:08:40

The guide says: "If you need to spec a nested sequential collection, you must use an explicit call to spec to start a new nested regex context. "

Alex Miller (Clojure team)18:08:49

well I mean I’d say that was your error

Alex Miller (Clojure team)18:08:02

but it’s a bug that you got a stackoverflow :)

borkdude18:08:14

garbage in, garbage out 😉

Alex Miller (Clojure team)18:08:15

it should have just said invalid

Alex Miller (Clojure team)18:08:27

it wasn't garbage though, just not accurate

stathissideris19:08:50

is there an equivalent of declare but for specs?

bfabry20:08:11

@stathissideris: you don't need to declare keywords before using them

rickmoynihan21:08:05

seancorfield: Thanks... at first the require in that function makes me wince... but it's actually a nice trick being able to include the generator in the spec and use the spec in production context without the generator dependency. Nice! xgen/string-from-regex is too nice to use! 🙂

seancorfield21:08:47

I use runtime require quite a bit. Very useful for conditional dependencies etc.

donaldball21:08:20

I seem to recall that s/atom-of was bandied about shortly after clojure.spec was released. Is that something we should anticipate in core or has it been discarded as a bad idea?

donaldball21:08:13

My current use case calls for like an s/promise-of, but I’m curious what the thinking is wrt specs for async values

Alex Miller (Clojure team)22:08:12

it was never bandied about by anyone from core :)

Alex Miller (Clojure team)22:08:17

I think it’s a bad idea