Fork me on GitHub
#clojure-spec
<
2019-01-09
>
ShaneLester16:01:42

What’s the normal way I should be handling speccing functions that have optional arguments?

Alex Miller (Clojure team)16:01:52

generally you should use regex ops (like s/cat) to spec args and ops like s/? to handle optional arguments within that

ShaneLester16:01:39

Cool. Thanks 🙂

jstew20:01:54

Is there a way to match an exact number of items in a collection or sequence? Let’s say I want to spec a seq or collection to have 3 and only 3 items in it?

jstew20:01:10

I suppose I could always assert that in the spec for the fn that uses the collection.

tangrammer20:01:38

As spec guide states 🙂

(s/def ::point (s/tuple double? double? double?))
(s/conform ::point [1.5 2.5 -0.5])
=> [1.5 2.5 -0.5]

https://clojure.org/guides/spec#_collections

jstew20:01:53

tuple! Thank you.

👍 5
Alex Miller (Clojure team)20:01:15

s/tuple is good for heterogeneous fixed-size (“slotted”) vectors

Alex Miller (Clojure team)20:01:44

s/coll-of with the :count option is good for homogenous (all items match the same pred) collections

Alex Miller (Clojure team)20:01:01

like (s/coll-of double? :count 3)

jstew20:01:32

That fits this use case better. Thanks, Alex.

Alex Miller (Clojure team)20:01:50

either will work and they conform and gen pretty similarly but I think one or the other usually has a better match on intent

ShaneLester21:01:50

I’m attemping to make a spec for something that can either be any number of vectors, or 0 or 1 strings. currently I have (spc/or :vectortype (spc/* vector?) :stringtype (spc/? string?)) but that doesn’t really seem to be working. (I know this is whacky but, using it to learn the nuances of spec

ShaneLester21:01:04

Anyone see if I am doing something obviously wrong there?

manutter5121:01:34

Looks fair to me, what are you getting from that that makes you say it’s not working?

ShaneLester21:01:46

Getting a message in-console saying that the function call does not match the spec when the argument that that spec covers is just a string

manutter5121:01:48

Function arguments need to be inside (spc/cat ...) maybe you’re missing that?

ShaneLester21:01:34

I guess this would have been more useful- here is the whole spec for the function currently (spc/fdef typog :args (spc/cat :props map? :children (spc/or :vect (spc/* vector?) :stringt (spc/? string?))))

ShaneLester21:01:42

so I do have cat. but not sure if im using it right

manutter5121:01:33

Do you have the :ret key in your fdef too? I’ve seen odd results when that was missing.

ShaneLester21:01:54

Hmm I dont, ill try adding that

manutter5121:01:09

Everything else looks good to me, with the caveat that I’m still getting comfortable with spec myself, so I might be missing something.

ShaneLester21:01:40

I just threw a :ret any? in there, but same results sadly. Yeah. It seems to logically make sense to me, and to others I’ve showed it to. Something strange going on perhaps…

ShaneLester21:01:44

I appreciate your help 🙂

Alex Miller (Clojure team)21:01:48

the s/or is not a regex op so inserts a new “level” of nesting

Alex Miller (Clojure team)21:01:15

so that is always expecting 2 args with the first a map and the second either a collection of 0 or more vector or an empty collection or a collection containing one string

Alex Miller (Clojure team)21:01:25

I don’t think that’s what you want

Alex Miller (Clojure team)21:01:02

I suspect changing the or to alt is probably closer, would at least match the string case you want

Alex Miller (Clojure team)21:01:38

but depends what you mean by “0 or 1 strings”

Alex Miller (Clojure team)21:01:52

if you mean “no 2nd arg” for “0 strings”, then that case is already covered by (* vector?), which can be 0 vectors

ShaneLester22:01:32

Ahh it was alt! That is what I needed. I did gloss over that in the api but apparently that did not make enough sense for me. haha. Thank you alex.

ShaneLester22:01:01

Also good point about the case of the arg not being there handled by the *, that is definitely true.