Fork me on GitHub
#clojure-spec
<
2016-06-19
>
Alex Miller (Clojure team)02:06:29

You can compose any kind of spec with and

Alex Miller (Clojure team)02:06:47

Note also that s/keys validates all keys in the map regardless of what's in req or opt

Alex Miller (Clojure team)02:06:07

So you don't technically have to list them as opt keys

akiel10:06:11

Has someone thought about specs for ex-data?

gfredericks13:06:56

(s/fspec :args ... :ret ... :throws ...)

cigitia13:06:56

In clojure.spec, is there a way to associate custom generators with your own functions, the way that clojure.spec.gen/gen-for-pred and gen-builtins associate generators with various clojure.core functions?

gfredericks15:06:13

cigitia: you can make a spec that has a particular generator associated with it using spec/with-gen

cigitia15:06:56

@gfredericks: Yes, though that requires either registering the spec returned by with-gen under a keyword, or using with-gen inline every time you use the function.

cigitia15:06:07

I’m wondering whether it’s possible to have generators when using functions directly—

cigitia15:06:35

Like how int? has a generator even when you use int? directly as a predicate, due to the way gen-for-pred works.

gfredericks15:06:09

I think you can say (def int? (spec/with-gen #(instance? Integer %) gen/large-integer))

gfredericks15:06:14

I might be lying

Alex Miller (Clojure team)15:06:45

There is more stuff coming in this area soon

akiel16:06:18

@gfredericks: is :throws discussed somewhere? I can’t find something about it.

gfredericks16:06:02

akiel: no I just made it up

gfredericks16:06:30

I was imagining an API that related to what you were asking about

akiel17:06:18

@gfredericks: Yes that’s exactly what I’m after. @alexmiller What do you think about exception data specs? As far as I see it, exception data keys are not even documented normally.

Alex Miller (Clojure team)17:06:13

We are not going to spec exceptions

Alex Miller (Clojure team)17:06:30

You could of course create specs for the ex-info map keys and I can see that possibly useful in functions that receive ex-info data after an exception has happened (to generate user errors or error pages etc)

akiel17:06:51

Do you think that the shape of the ex-data should be public API of a function or do you are more in line with Joshua Bloch: Effective Java Item 57: Use exceptions only for exceptional conditions were he suggests that exception should not be used for decision making.

Alex Miller (Clojure team)18:06:07

Unless you're abusing it for performance :)

akiel19:06:53

@alexmiller: sorry for asking further - yes public or yes not-public?

hiredman19:06:48

not specing execeptions makes a lot of sense

hiredman19:06:16

1. spec is not a type system 2. spec is primarily about specifying data and exceptions are not data, they are weird control flow operation in a language 3. specs for functions specify what valid argument data looks like, and given that valid argument data, what a valid result looks like, and that is how the generative stuff works, and in that model there is no place for exceptions

hiredman19:06:58

given a function F, if F throws E, to ensure correctness you want to look at all callers of F, and ensure that they handle E correctly, which is exactly the opposite of how the generative testing works (if I understand correctly)

akiel19:06:14

@hiredman: in case API’s don’t use exceptions for control flow I’m with you. But than we don’t need ex-info and ex-data at all and should stop build API’s which put data into exceptions

akiel19:06:02

s/conform is a good example for an API not using exceptions - it returns ::s/invalid

bhauman19:06:40

Is there a way to validate that you have defined all namespaced keywords in the your spec definitions? And get a warning if some are missing?

hiredman19:06:21

write a predicate that checks the spec registry

bhauman19:06:01

hmmm ... so say compose a macro over spec/keys, capture the key args and and then warn if if the keys are not present in the registry? or were you thinking something else?

bhauman19:06:03

if you wanted to verify everything with a single call though it seems like you would have to parse the describe of each of the registry members

hiredman19:06:38

user=> (s/valid? (s/map-of #(if (and (keyword? %) (namespace %)) (contains? (s/registry) %) true) ::s/any) {:a 1})
true
user=> (s/valid? (s/map-of #(if (and (keyword? %) (namespace %)) (contains? (s/registry) %) true) ::s/any) {::a 1})
false
user=> (s/def ::a ::s/any)
:user/a
user=> (s/valid? (s/map-of #(if (and (keyword? %) (namespace %)) (contains? (s/registry) %) true) ::s/any) {::a 1})
true
user=> 

bhauman19:06:57

cool yep, but was thinking of a different use case, where you are inspecting the self referential integrity of the registry itself

hiredman19:06:55

not sure I follow? that s/map-of spec will fail if given a map with namespaced keys that are not speced

hiredman19:06:18

I think I get it now

hiredman19:06:15

yeah, spec seems to be slightly later binding than clojure is

bhauman19:06:11

yeah, it's doable, but I think it would be nice to have some help beyond describe

hiredman19:06:19

you'd like ::foo to throw an error earlier then when you run the spec, basically, like clojure does with vars

bhauman19:06:27

I'd like to do ( check-missing (clojure.spec/registry))

bhauman19:06:39

to help me in the repl so that I can see if I forgot something

hiredman19:06:20

that might not be currently possible, I don't think specs have a way to get all the specs they depend on

hiredman19:06:36

which might be an interesting enhancement

bhauman19:06:20

exactly, it would be nice to have a spec walker

bhauman20:06:17

or at least a corollary to describe that returns the actual internal data