Fork me on GitHub
#clojure-spec
<
2019-01-20
>
lambdam08:01:50

@misha thanks for this solution. I did that in a way for something a bit different and the problem I bumped into was that you cannot require the namespace containing the specs in another namespace and use it with a shortcut. Let's say the previous code was in a namespace a.

(ns b
  (:require [myapp.lib.a :as a]))

(s/valid? ::a/foo <whatever>)

(s/valid? :quz/resource <whatever>) <-- I have to remember that this comes from namespace myapp.lib.a
and doing this
(ns b)

(s/valid? :quz/resource <whatever>)
the dependency graph of spec definitions is not right and the compiler will complain (it happened to me and I spent time renaming a lot of specs) Thus, even though I can do it, I tend to feel that it's a clumsy solution.

misha13:01:19

tying all specs' ns to file ns - is often not a good idea

lambdam08:01:47

Another question that comes to my mind, how can I validate a map whose keys are string (typically data from an HTML form). Doing this (s/def ::form-data (s/keys :req ["foo" "bar"])) is half of the spec. I'd like to qualify the content of the keys. Again I feel like missing a syntax like this: (s/def ::form-data (s/keys :req [(s/key "foo" string?) (s/key "bar" int?)])).

lmergen09:01:59

i keep running into an issue with managing the complexity of my specs, and was wondering whether i'm "doing it all wrong". specifically, of quite a few specs, i need to have multiple variations of the same "schema", depending on the context. to give an example, a user should not need to have an ID before it is inserted into the database, but it does need an ID when it is. this is a simple example, but this pattern repeats. since ideally, i want my code to be able to declare whether it expects a a "stored user" or not, i currently compose these things as follows:

(s/def :user (s/keys ...))
(s/def :user/inserted (s/merge :user (s/keys ...))
on the surface this seemed like a good idea, but after a while of using this, i discovered downsides to this. most importantly: as soon as you have other specs that depend upon inserted users or not (e.g. a "company" vs "inserted company"), you repeat this pattern a lot, even when there is not necessarily a difference between a "company" and "inserted company". as an alternative to this, i was thinking of making the state an explicit property i can multi-spec on. this makes the approach more data-driven. but then i wouldn't be able to directly say, "i expect an inserted user" in the code through specs anymore. are there any alternatives to this ? i hope my question is making a bit of sense 🙂

lmergen09:01:15

now, code cannot just fdef anymore saying it expects a ::shape/cube or a ::shape/sphere, it can only fdef on ::shape

lmergen09:01:13

this is another discussion on the same topic => https://lispcast.com/reduce-complexity-with-variants/

ericnormand16:01:10

@lmergen I think Rich Hickey has noticed that problem, too

ericnormand16:01:29

he talked about it at the conj and hinted at a big change to spec to make this easier

lmergen16:01:52

yeah I saw that, sounds very promising!

ericnormand16:01:59

basically, you define a map spec separately from the selection

ericnormand16:01:25

which lets you separate out the definition of the entity from the context

lmergen16:01:35

yes so you declare what you need rather than what something is

lmergen16:01:05

ok thanks I kind of forgot about that

ericnormand16:01:18

i have faced this same problem myself

ericnormand16:01:47

proliferation of specs because, for instance, if you have all the CRUD operations, they each require slightly different data

ericnormand16:01:55

though you'd like to think of them as operating on the same entity

borkdude16:01:56

it’s the same problems that type systems without extensible records have

lmergen16:01:06

so now spec becomes a category system :)

borkdude16:01:31

what’s that

lmergen16:01:53

sorry I meant category as in category theory

lmergen16:01:05

rather than describing types you describe traits

lmergen16:01:05

I am fairly sure I have just mentioned a few forbidden words

borkdude16:01:26

— awkward silence —

Alex Miller (Clojure team)17:01:06

I think it’s most useful to think of it as oriented around value sets, as described by predicates

lmergen17:01:24

I’ll be watching your progress alex, just found the new spec repo

Alex Miller (Clojure team)17:01:12

maps are composites of their attributes and the key is that semantics are derived from the attributes, not from the composite itself

lmergen17:01:34

so they become self describing ?

Alex Miller (Clojure team)17:01:38

not sure that’s the important bit

Alex Miller (Clojure team)17:01:00

the new idea from Rich’s last keynote is that different functions can speak more precisely about which subset of the composite it cares about, and we can have better tools for describing what a function does with those inputs wrt to the output