Fork me on GitHub
#clojure-spec
<
2016-11-02
>
vandr0iy09:11:16

Hi, #clojure-spec! came to ask: what's the difference between clojure.spec/map-of and clojure.spec/every-kv?

bhagany12:11:27

@vandr0iy map-of checks all the entries of the map, while every-kv samples a subset of the entries

bhagany12:11:19

every-kv is designed to be used with maps that may be large

vandr0iy12:11:48

nice explanation, thanks @bhagany !

lopalghost13:11:01

Any thoughts on writing separate specs for input data that needs to be coerced, vs using spec/conformer?

mpenet13:11:56

coerce separately from your main specs yes, with or without spec

mpenet13:11:11

it gets very messy otherwise imho

lopalghost13:11:59

That's what I'm finding to be the case

lopalghost13:11:17

The only problem is I'm duplicating my validation logic, because I want to be able to detect invalid data at the point of entry

lopalghost13:11:44

I'm using spec in both cases because the generative testing is super-helpful

mpenet13:11:10

you can create predicates separately that you re-use on both specs

mpenet13:11:27

but yes, there will be duplication here and there

drewr13:11:04

what are you all doing to cleanup after check on a fn with side effects?

drewr13:11:34

it doesn't look immediately possible with :fn unless I pass context back through the return value

drewr13:11:03

I suppose I could with-redefs in there, but that doesn't feel right

Alex Miller (Clojure team)14:11:22

@vandr0iy additionally, every-kv will not conform its keys or values (because it doesn’t check all of them) whereas map-of will conform all values (and optionally all keys)

Alex Miller (Clojure team)14:11:05

@drewr don’t write fns with side effects? :)

Alex Miller (Clojure team)14:11:29

seriously though, you might look at the stub and replace options on stest/instrument

drewr14:11:22

yeah, would love to avoid them, but have to do things other than burn cpu 🔥

drewr14:11:36

cool, didn't notice those opts on instrument

Alex Miller (Clojure team)14:11:37

particularly for the case where you are checking a function that calls a side-effecting function

Alex Miller (Clojure team)14:11:55

you can stub or replace it instead

drewr14:11:14

I didn't think to look at instrument, though, because this goes farther than just args checking

drewr14:11:00

seems like something that would happen with test.check... ie, a function that somewhere ends up writing a value to a db, and I need to make sure that value is deleted (or the db is removed)

Alex Miller (Clojure team)14:11:12

you should instrument, then check

drewr14:11:51

right now I'm doing the whole enumerate-namespace -> check -> summarize-results dance, sounds like I need to break out of that pattern

gfredericks14:11:25

@lopalghost I played around with those issues in https://github.com/gfredericks/schema-bijections; I'd love to see that sort of thing implemented for spec

jrheard15:11:53

what’s the alternative to the pattern @drewr gives above?

jrheard15:11:05

i haven’t used the stub-and-replace options alex mentions, so maybe you guys just mean that using them necessitates breaking out of the pattern he gives

jrheard15:11:17

just curious 🙂

drewr15:11:25

@jrheard I'll give you an example when I have one 😂

lopalghost15:11:06

@gfredericks I think spec/conformer is a pretty good solution to the problem of coercing back and forth, at least

lopalghost15:11:19

The problem is you lose information about the input, making explain and check less useful

lopalghost15:11:02

I've tried writing some DSLs to generate specs, but I was never really happy with them

gfredericks15:11:24

Yeah, I remember an earlier conversation that ended up recommending mapping to new specs rather than just conforming

gfredericks15:11:04

But spec isn't good at, e.g., describing maps with string keys, though :/

mpenet15:11:47

anything other than keyword keys (sadly)

mpenet15:11:07

you end up having to resort to weird, half working, set + map-of hacks

zane15:11:46

It feels like passing around conformed values is discouraged. Is that correct?

mpenet15:11:20

I often wonder why namespaced keys couldn't just be a collection of keywords, since that's just values

mpenet15:11:37

I guess there's a good reason behind this (interning magic leading to better perf ?)

lopalghost15:11:12

I don't like set + map-of because it makes explanations less clear

mpenet15:11:18

[:some-ns :some-key]

lopalghost15:11:36

It might be better to coerce the keys in a separate step

mpenet15:11:46

@lopalghost more importantly it breaks link between key and value

mpenet15:11:01

it just guarantees the key is here

mpenet15:11:28

so yeah either coercion, or it might be better to just have a custom predicate to validate such maps

Alex Miller (Clojure team)16:11:23

you can use every on maps to describe the map entries as k-v tuples

mpenet16:11:49

neat, I didn't think of that one

Alex Miller (Clojure team)16:11:03

like (s/every (s/or :name-entry (s/tuple #{”name”} string?) :id-entry (s/tuple #{”id”} int?)) :kind map? :into {})

Alex Miller (Clojure team)16:11:29

but whatever or’ed entry types you need

Alex Miller (Clojure team)16:11:06

for non-kw key maps, this can be a good approach

Alex Miller (Clojure team)16:11:52

(that’s how every-kv and ultimately map-of are actually implemented)

nwjsmith19:11:45

Where can I vote for adding docstrings to specs?

nwjsmith19:11:55

I think I saw it being discussed here a few weeks ago, and I though “who would ever want to do that?” Turns out I am someone who would want to do that.

potetm20:11:38

Is it appropriate to give more rationale for that ^ ticket in a comment on JIRA?

potetm20:11:30

I've thought about it a little bit, and I think there's a really good justification for adding it.

jasonjckn22:11:09

is there a general recommendation for versioned schema?

jasonjckn22:11:14

multi spec dispatching on version tag?

jasonjckn22:11:49

what if i'm evolving my spec over time, deprecating fields, introducing new ones, changing existing ones.