Fork me on GitHub
#clojure-spec
<
2016-08-04
>
misha02:08:47

good morning. is there a short answer to

are clojure.spec's - a replacement for {:pre ... :post ...} condition-map parameters?
? (assuming sparse usage of the latter)

gfredericks02:08:01

@misha from my perspective, mostly yes

Alex Miller (Clojure team)02:08:46

@thegeez you can definitely use conform to destructure values if that’s useful (particularly useful in macros when decoding syntax). Cost is not free of course but will get better.

Alex Miller (Clojure team)02:08:39

@gfredericks it’s easy to add a generator with s/with-gen. There are combinations of gen/bind and gen/fmap that can help you work from a model of your data towards generated values. The next (I think) screencast from Stu is going to talk about this more.

gfredericks03:08:13

@alexmiller: but it's not easy to use with-gen to modify the default generator, unless I'm missing something

Alex Miller (Clojure team)03:08:40

But if you have just the base spec, you can pull its gen and feed it into fmap

calvis16:08:33

is there any easy way to spec a map where the required keywords depend on the values in the map? > e.g. if (:a m) is 5 then m should also have a :b keyword I realize this can be done with manually defined predicates and then manually defined generators

eggsyntax16:08:49

Seems like you could cobble it together with s/or, defining each possible combination separately (&, in your example, presumably two separate specs for the options for :a). But that’s hardly elegant...

eggsyntax16:08:27

ie an ::a-5 predicate and a general ::a version

eggsyntax16:08:09

with one alternative containing the former as well as the :b keyword, and the other alternative containing the latter and not containing :b.

calvis16:08:30

I’m specifically asking for an elegant way, before I go and write a macro that does it

eggsyntax16:08:50

Yeah, just brainstorming.

calvis16:08:22

it seems like this would be a pretty common thing to do at least

bsima18:08:40

Is it preferred to put specs in a separate namespace, like how clojure.java.jdbc does it? --> https://github.com/clojure/java.jdbc/blob/f9fe3dde5b4bc5f1a5b5a79ffb5374fad3377b0b/src/main/clojure/clojure/java/jdbc/spec.clj

gfredericks18:08:54

@bsima: I think java.jdbc does it to be backwards compatible with older versions of clojure

seancorfield18:08:10

@bsima: FWIW, we’re following a similar pattern at World Singles where our specs are in one namespace and we pull that into other namespaces as needed — but that’s partly because nearly all of our specs so far are very data-focused rather than function-focused.

seancorfield18:08:50

We haven’t yet decided how that will play out when we’re defining system boundary APIs on top of those specs.

seancorfield18:08:41

And, yes, java.jdbc needs to support Clojure back to 1.4.0, as @gfredericks says.

bsima18:08:45

in a recent cognicast rich hickey mentioned using specs as a way to version a codebase, like "if your code matches this set of spec keys then we didn't break anything with this new release" (paraphrasing)

bsima18:08:17

so, I think that's an interesting way to approach specs, and an argument for separating specs from code

bsima18:08:17

most of the specs i've written so far have been fdefs, it almost feels like racket's contract system

Alex Miller (Clojure team)19:08:56

for another data point, we are currently working on putting clojure.core specs in the namespace clojure.core.specs

Alex Miller (Clojure team)19:08:30

not saying that following the pattern is the only way or best way to do it for anyone else’s particular situation though

rickmoynihan21:08:03

FWIW - I've been experimenting with the specs in a sidecar namespace, but with the fdefs in the foo namespace beneath the functions... not been using spec much yet though - so not sure how it'll work out

bbrinck21:08:02

I've been placing the fdef right above the function definition. I find that's the most valuable place from the perspective of providing documentation. I like seeing the specs, the arg names, and the docstring all in one place.

bbrinck21:08:43

but i suspect that specs for common data types will go in a different namespace that can be used in many namespaces

rickmoynihan21:08:18

you can do that? I'd assumed because fdef takes a symbol for the function its annotating that it would have to come after the definition of the function

bbrinck22:08:14

@rickmoynihan: yeah it works for me:

(s/fdef my-new-fn
        :args (s/cat :int integer?))
(defn my-new-fn [x]
  (+ x x))

(stest/instrument `my-new-fn)

(comment
  (= 2 (my-new-fn 1))    ; => true 
  (= 2 (my-new-fn nil))  ; spec error
  )

rickmoynihan22:08:38

agree that they're better above the definition

seancorfield22:08:27

Just remember that if your fdefs are elsewhere, you need a qualified symbol name (see https://github.com/clojure/java.jdbc/blob/master/src/main/clojure/clojure/java/jdbc/spec.clj where I updated this for Alpha 10 — unqualified symbols worked in an earlier Alpha if you just referred them in unqualified).