Fork me on GitHub
#clojure-spec
<
2017-08-02
>
Niclas11:08:33

Could someone help me understand why for the given example fn

(defn my-fn [selector]
  (condp = selector
    1 :b
    2 :c
    false))
it fails on the :ret spec when calling the fn with the following spec
(s/fdef my-fn
        :args (s/cat :selector any?)
        :ret #{false :b :c})
but not for the following spec
(s/fdef my-fn
        :args (s/cat :selector any?)
        :ret (s/or :a #(= % false)
                   :b #(= % :b)
                   :c #(= % :c)))

mpenet11:08:44

prolly comes down to this: (s/valid? #{false 😛 :c} false) -> false or (#{false} false) -> false

mpenet11:08:04

since it will return the value matching in the set (false) this will break

mpenet11:08:01

typical quirk with Sets

scaturr11:08:18

Is there some established/idiomatic way to use spec with core.async? Particularly when reading from a channel?

scaturr11:08:30

Or would it come down to adding a spec to a function that pushes on to the channel you are reading from?

scaturr11:08:05

Probably way too broad of a question… lol

mpenet11:08:06

@looveh so in short, use contains? (and specify a custom :gen if you need to)

Niclas11:08:49

@mpenet Ah, that’s quirky indeed, thanks!

schmee12:08:16

unless you have a transient collection, for which contains? doesn’t work

matan13:08:13

@camdez thanks for last week's answer about clojure.spec.alpha/invalid in the context of spec's code stability 🙂

camdez13:08:59

@matan You’re very welcome. I hope it was helpful.

matan13:08:56

@camdez yes, it certainly was!

matan13:08:12

@camdez will I bump into a lot of stuff coming from its "alpha" namespace when using spec today?

camdez13:08:58

@matan I don’t think you’ll run into much.

cddr15:08:45

Am I correct in thinking that spec would be the wrong tool to assert relationships between keys in a map. For example, lets say we're representing a bill split between n folks, can/should you leverage spec to assert that the sum of amounts under the payees key is greater than or equal to the top-level amount? If not spec, is there some other library that allows you to organize validations like these in a way that lends support to generating good error messages

{:amount 60
 :payees [{:name :andy
           :amount 20}
          {:name :rich
           :amount 20}
          {:name :alex
           :amount 20}]}

mpenet15:08:16

seems fine to me, could be a (s/and (s/keys ...) sum-amounts>=total?)

mpenet15:08:24

then it's just pattern matching on the explain to return something more "flat" for error messages (depending on your usage), which you can do with/without spec (you could build it with a spec errors conformer that maps to your precise error types)

ghadi15:08:26

agree with @mpenet. i don't think it's the wrong tool at all. just a predicate!

cddr15:08:28

Doh! It never occurred to me that (s/keys) could be anded.

ghadi19:08:54

on the contrary, I really don't think you need a library to describe a datastructure -- this is literally the rationale for clojure.spec

ghadi19:08:10

what cddr wants is a predicate that applies to a collection

ghadi19:08:48

Similar to how fspec provides the :fn spec that relates a function's :args and :ret

caio19:08:48

you're trying to define an invariant about a data structure, not a contract. I like the idea of separating those concepts (thus using a library to define invariants looks like a good idea)

caio19:08:36

but yeah, that's just being pedantic, so for a simple structure like this, I agree adding a new dependency is probably an overkill

cddr19:08:34

I definitely prefer using the standard lib when it supports what I'm trying to do. Cheers for the suggestion though. Looks interesting 🙂

bfabry19:08:17

I think invariant is just a library for defining data structure predicates. if you have to write enough/complicated enough data structure predicates I think it would be useful to use with spec. similar to how specter is useful if you've got to do enough deeply nested data manipulation

caio19:08:47

@cddr yeah, it is! I'm probably biased towards it because I used it and liked it a lot hahaha. In my case, I had to define invariants on a custom markup language

caio19:08:34

so spec wasn't going to help there

rgdelato21:08:26

is it possible to define a spec for map keys without defing a separate spec for each key? I guess what I have in my head is something like:

(s/keys :req-lit {:first-name string?
                  :last-name string?
                  :email (s/and string?
                                #(re-matches email-regex %))})
...where you could spec map keys inline?

gfredericks21:08:34

I think that's an intentionally excluded feature

rgdelato21:08:01

is there anywhere where I could read up on why that's the case?

bbrinck21:08:10

https://clojure.org/about/spec - “Map specs should be of keysets only”