Fork me on GitHub
Alex Miller (Clojure team)00:11:51

@zane no, although that's been asked a lot


@alexmiller besides core, do you use a separate namespace for the separate file?


i guess yes if you want to load them with a require, no if you’re going to load them with load-file from the main ns?

Alex Miller (Clojure team)00:11:53

I think it's easier to use a separate ns


@alexmiller one weird thing with that, spec, and namespaced keywords in general, is that i find myself doing this:


(create-ns ‘mynamespace) (alias ‘m ‘mynamespace)


so that i can refer to things w/o a cyclic dep

Alex Miller (Clojure team)00:11:10

There is a patch I wrote to auto-create

Alex Miller (Clojure team)00:11:23

So just alias would be enough


that would be welcome

Alex Miller (Clojure team)00:11:30

Rich hasn't looked at it yet



Alex Miller (Clojure team)00:11:39

Well, it's already screened, just waiting for a slice of rich time


not complaining - you know i’m in your camp on the processes 🙂


and I’m hoping that such a useful function makes it into the core library.

Alex Miller (Clojure team)01:11:33

Not planning on it right now


i’m using spec in anger to solve a bug in an otherwise un-spec’d namespace right now


i haven’t found the bug i am looking for, but i did find three other lurking bugs


it’s kinda awesome.


@alexmiller Curious as to why not. defspec-test, or something similar, seems to be low hanging fruit for adopting spec’d function tests, into a projects overall test suite.


@twashing the one issue with the macro is it only counts generative tests as one test in the test summary (e.g. You run 1000 generative tests but the summary results only count it as one). I've been meaning to add it but haven't had time.


If something like it isn't included in Clojure core when 1.9 is released then we can move it into a micro library instead of a gist


@kenny Right, I was thinking just that. Kewl 👍


@kenny Would make may day if it found its way into 1.9

Alex Miller (Clojure team)14:11:36

in general, spec tests have a different shape than example based tests. I think it’s good to step back and think about why or if it’s valuable to force everything into the shape of something that clojure.test can run. This feels to me like the limits of our tool (particularly reliance on lein test to run and report everything) are affecting our ability to think about the problem. Why does there need to be only one kind of test runner? Why does there need to be only one kind of test? Generative tests are (by their nature) longer running and often don’t mix well with example based tests in a single suite. There is more to say on this.


Is there a way to use conform without destructuring the values? (i.e. I’d like have an s/or within the spec but not have change the original value).

Alex Miller (Clojure team)15:11:58

no, but you can use a conformer of val to undo conforming an or

Alex Miller (Clojure team)15:11:59

(s/and ::my-or-spec (s/conformer val))

Alex Miller (Clojure team)15:11:56

Rich toyed with s/nonconforming (still there but not in docs) but I suspect it will probably get removed before final release


@bplatz You can fudge it by wrapping your or spec like this: (s/and (s/or ...) (s/conformer val))


Though this is probably dangerously close to meat grinder territory again 😄


Oops, sorry, I overlooked the first reply of yours @alexmiller


The use case here, which I’d think is a decent one, is validating and coercing JSON input - but downstream code expects data in a specific way.


Thanks for the s/and tip, I’ll use that for the time being until either it gets officially supported or we just use a different mechanism to coerce the data.


How does one go about speccing a multimethod? Can the different defmethods have different :args?

Alex Miller (Clojure team)16:11:58

I don’t think s/fdef works on multimethods right now


@alexmiller Ok, but if I don’t use multimethods but dynamically dispatches inside the function, can I somehow define a relation between the function arguments i.e.: > If the first argument is a number, then the second should conform to :c/myspec1 , but if the first argument is a keyword then the second argument should conform to :c/myspec2?

Alex Miller (Clojure team)17:11:32

there are a couple options

Alex Miller (Clojure team)17:11:03

one is to write an fdef with a :fn spec which can describe a relationship between args and ret

Alex Miller (Clojure team)17:11:25

another is to use s/multi-spec which can yield a different spec based on a separate multimethod

Alex Miller (Clojure team)17:11:57

the latter is really ideal for functions where the spec is open for extension after the fact


I checked into multi-spec, but then the input has to be a map right?

Alex Miller (Clojure team)17:11:31

I think there are examples of both in the guide

Alex Miller (Clojure team)17:11:51

as long as you give it a multimethod that chooses the proper spec based on the input


@alexmiller Ah, just like multimethods the second argument is not a keyword but a function, but in clojure a keyword can be a function… Then that’s exactly what I need.)

Alex Miller (Clojure team)17:11:02

you will likely need a custom retag function too, but that’s not a big deal

Alex Miller (Clojure team)17:11:16

check the docstring for the details


I have a clojure-spec/clojurescript question if anybody can help. I suspect it’s obvious.


I have the following -

(s/def ::box (s/keys :req [::c/height ::c/width ::p/x ::p/y]))
(defn- right [box]
  (+ (:width box) (:x box)))

(defn- bottom [box]
  (+ (:height box) (:y box)))

(defn intersect? [box-one box-two]
      (> (::p/x box-two) (right box-one))
      (< (right box-two) (:x box-one))
      (> (:y box-two) (bottom box-one))
      (< (bottom box-two) (:y box-one)))))

(s/fdef intersect?
        :args (s/cat :box-one ::box :box-two ::box)
        :ret boolean?)


What I can’t do is get the intersect? to actually assert when I call it incorrectly


So for instance:

cljs.user=> (require '[cljs.spec :as s])
cljs.user=> (s/check-asserts?)
cljs.user=> (box/intersect? {} {::c/width 100})


I’m sure the problem is between brain and keyboard, but I’m pretty stumped. Shouldn’t this go kerblooie?


check-asserts? governs any s/asserts you have in the code, but you don't have any


I thought fdef would instrument the function - thereby adding the asserts automagically


when testing you can run instrument, which turns on that sort of thing for testing, but you will also get bits of generative testing happening, so it is not something you generally want to turn on


@paytonrules you want to run (s/instrument)


I was going by this from fdef docs

"Once registered, function specs are included in doc, checked by instrument,


But apparently ClojureScript doesn’t have the instrument function


really? that surprises me


instrument is in clojure.spec.test (not sure what translation to that you need to do for clojurescript)


oh yeah, sorry, instrument is in a different ns


from what I understand, always on checking is a non-goal for spec


Aha - it was the clojure.spec.test that I missed bit that I missed.


Thanks a lot. It would appear then that spec’ing functions that you aren’t actively doing property based testing on, or debugging, may not be a useful endeavor.


@paytonrules I'm not sure that's true, I think there's still value in specing things and having instrumentation turned on for development/test


I wonder how much slower things will be turning on instrument in development will be


unless you're getting into speccing function arguments I don't expect instrument will be super slow in a development context


Maybe to turn it on and turn it off. I’m making an HTML5 game so if I spec everything it’ll hurt.


if you turn on instrument, invoking functions that are spec'ed will also cause those functions to be genertively tested against those specs


@hiredman I'm not sure that's right? I think it only generatively tests functions that you pass as arguments, to make sure the argument satisfies the fdef


user=> (defn foo []
  #_=>   (println "foo!"))
user=> (s/fdef foo :args (s/cat) :ret nil?)
user=> (clojure.spec.test/instrument)
user=> (foo)


the exact behavior is whatever, my point is, don't turn it on in production


you don't want to be running generative tests in production