Fork me on GitHub
#clojure-spec
<
2016-11-23
>
yonatanel10:11:01

If I define specs such as :event/type, it's something that will likely be defined by more projects, so is the best practice to have a fuller namespace such as :org.my.event/type? This will deviate from the shorter form of my Datomic attributes which I don't want to prefix with the organization name all over the place. (I assume specs can collide being in the same process, while in Datomic I control what I put there)

yonatanel12:11:27

Perhaps the question is about specs of internal vs external data.

Alex Miller (Clojure team)12:11:38

Yes, you should use a sufficiently unique namespace

Alex Miller (Clojure team)12:11:54

But if you control what namespaces you're using, "sufficiently" can be pretty short

yonatanel13:11:20

Being paranoid, maybe it could be nice to have separate non-default registry instances, or attaching a spec to a key when calling s/keys somehow.

gfredericks15:11:16

@yonatanel if you're paranoid then you can just use sufficiently unique namespaces

rickmoynihan15:11:18

On a similar note, what’s the suggested way to spec a format you didn’t define, that defines the same key with different values/specs… Basically is there an alternative to using s/keys when I have two different specs that share that prefix? Or should I just move the conflicting definitions into different namespaces?

gfredericks15:11:04

Different namespaces

gfredericks15:11:50

It just occurs to me that spec can't describe something where a namespaced keyword has varying meaning

rickmoynihan15:11:01

gfredericks: that’s the problem I have

gfredericks15:11:03

Which I imagine is rare

gfredericks15:11:27

Who subjected you to this

rickmoynihan15:11:37

well maybe I don’t have the problem

rickmoynihan15:11:20

I mean I can work around it by defining the specs in different namespaces

Alex Miller (Clojure team)15:11:38

If you have that problem, you may be doing it wrong :)

rickmoynihan15:11:50

entirely possible

Alex Miller (Clojure team)15:11:20

if you have unqualified keys, then you can deal with this using s/keys and :req-un with different namespaced specs

Alex Miller (Clojure team)15:11:44

if you have qualified keys, then… use the namespaces to differentiate different semantics

rickmoynihan15:11:46

alexmiller: yeah I think I just need to define some new namespaces for those extra keys

rickmoynihan15:11:52

out of interest is it possible to do (s/def :foo/spec ,,,) and have that work with keys :req-un?

gfredericks15:11:24

Looks normal....?

gfredericks15:11:01

Every registered spec has to have a namespace

rickmoynihan16:11:48

gfredericks: What I mean is - is the above possible instead of having to create a new namespace e.g. can you do the above instead of needing (ns blah.foo) (s/def ::spec ,,,)

gfredericks16:11:31

Code namespaces and keyword namespaces are mostly independent

rickmoynihan16:11:10

ok that’s what I thought, it’s just not working - presumably for another reason

rickmoynihan16:11:36

its ok I fixed it

rickmoynihan16:11:44

code blindness

gfredericks16:11:59

The eternal bug

rickmoynihan16:11:45

yup - that’s one thing about software development, you have to be pretty thick skinned as you’re continually told by the computer that “you suck! Another mistake, are you some kinda noob? Oh and another mistake, you really aren’t good enough…” ad-infinitum… I have a hypothesis that this is why people don’t stick it out as a career

rickmoynihan16:11:44

you basically have to be a bit of a masochist to stick it out

yonatanel16:11:38

@rickmoynihan My take on this is that you can't yet have "wonderful" mistakes when programming, unlike art where if you use some new material or do a quick sketch it can still look good and expressive.

rickmoynihan16:11:23

yonatanel: yeah… programming is so precise one bit out and it's a catastrophic failure and how many trillion bits are we handling these days?

rickmoynihan16:11:46

it’s a miracle of engineering anything works at all

seancorfield18:11:29

(for me, it’s sheer stubbornness: “I will not be beaten by an inanimate object!” so I must “defeat” the computer 🙂 )

rickmoynihan18:11:34

a quixotic quest if ever there was one 🙂

aengelberg18:11:40

The docstring of s/def indicates that one can provide a symbol instead of a keyword as the name for a spec, but I cannot find any examples of that. What use case is that for?

bfabry18:11:48

@aengelberg s/fdef is equivalent to (s/def symbol (s/fspec ...))

bfabry18:11:22

same as defn is (def symbol (fn ...)) 🙂

aengelberg18:11:03

@bfabry: interesting, thanks. So when would one use specs that have been set to a symbol?

bfabry18:11:00

well you're implicitly using them anytime you use instrument

bfabry18:11:46

explicitly? I dunno. I can't think of a good one off the top of my head, but that doesn't mean there's not

bfabry18:11:12

you could use the registered fspec's to spec a function to be passed in as

(s/or :this `this :that `that :the-other `the-other)
I guess. seems a little contrived

hiredman19:11:53

as of the 1.9 alphas, macro inputs are checked via spec, so because the spec is named with the same symbol as the macro, the ns macro's inputs are checked with that spec

aengelberg19:11:30

thanks, that helps a lot

aengelberg19:11:05

Suppose I have a datatype (or {:foo/name-type :keyword, :foo/name :my-foo} {:foo/name-type :string, :foo/name "my-foo"}). How can I write that in clojure.spec, if s/keys forces me to commit to one possible spec for a given key?

bfabry19:11:12

foo/name will need to be an or spec, then you can enforce the dependency using and with a predicate

aengelberg19:11:52

Is the fact that :a/b/c gives me a keyword with namespace "a" and name "b/c" an implementation detail?

aengelberg19:11:13

Because I could technically leverage that with :req-un to have different versions of a namespaced key.

hiredman19:11:51

I think that is sort of a design decision baked in to spec, a namespaced key should only ever be mapped to the same kind of thing

hiredman19:11:22

spec is sort of a global schema for data in your program

hiredman19:11:23

so similar to having a sql table with a schema where you say a column has some type, you don't really say sometimes this column has this type, some times it has this other, depending on where the data comes from

bfabry19:11:57

I would guess that a symbol with / in its name is undefined in terms of what will happen

bfabry19:11:08

"Symbols begin with a non-numeric character and can contain alphanumeric characters and *, +, !, -, _, ', and ? (other characters may be allowed eventually)."

bfabry19:11:37

'/' isn't in that list, so I'd say you're off the edge of the map if you use symbols with it in them

aengelberg19:11:51

Got it, makes sense. In this case I am working with an existing program that has keys not set up with that philosophy, so I'm just trying to figure out if there's any way I can fall back to more verbose but more flexible behavior a la prismatic schema. Sounds like not.

aengelberg19:11:02

@bfabry: I was referring to keywords, not symbols.

bfabry19:11:55

keywords have the same rules as symbols, but can't contain .

hiredman19:11:57

there was a discussion about / in keywords, and it comes up over and over again because clojure allows a larger range of inputs than it should in many places

hiredman19:11:18

answer is just don't do that

bfabry19:11:36

yes, you can make all sorts of symbols and keywords that the documentation doesn't say is permitted, which is very unfortunate

aengelberg19:11:13

So what you're saying is that I should use the :a/b/c keyword NOW while I can before it becomes officially unusable.

aengelberg19:11:22

Just kidding. I don't in fact want to watch the world burn.

aengelberg19:11:31

Is this intentional?

user> (s/explain #{1 2 3} 4)
val: 4 fails predicate: :clojure.spec/unknown
nil
Specifically the "unknown" part. Seems like the predicate should be more informative when it fails.

bfabry19:11:17

special case. if you def'd that predicate to the registry you'd get better message

bfabry19:11:40

user=> (s/def ::foo #{1 2 3 4})
:user/foo
user=> (s/explain ::foo 5)
val: 5 fails spec: :user/foo predicate: #{1 4 3 2}
nil

hiredman19:11:48

user=> (s/explain (s/spec #{1 2 3}) 4)
val: 4 fails predicate: #{1 3 2}
nil
user=>

bfabry19:11:49

basically, explain is not a macro

hiredman19:11:54

spec tries to transparently treat things that could be specs (like sets and predicates) as specs

hiredman19:11:03

so those generally work

hiredman19:11:46

but there are places where it doesn't, like in the message, there, I suspect its and easy fix if you open an issue

hiredman19:11:54

s/explain must be calling whatever part of the spec protocol implements s/form on the set, and the spec protocol has a fallback on object which returns the unknown keyword

hiredman19:11:55

there may already be an issue, spec is only out in alphas

Alex Miller (Clojure team)19:11:19

@aengelberg re the unknown in explain - that’s a known bug and will be fixed

Alex Miller (Clojure team)19:11:35

I’ve worked on it a bit but waiting for some feedback from Rich

Alex Miller (Clojure team)19:11:56

I should probably log an actual jira for it so I can just point people to it

Alex Miller (Clojure team)19:11:06

re your prior question, depending on your goal, you can s/def :foo/name with an s/or or you could define different s/keys specs and s/or those

Alex Miller (Clojure team)19:11:17

but the latter seems like it would be papering over the true range of variability in the spec for that attribute

Alex Miller (Clojure team)19:11:44

if your goal is really coercion, then there may be other options (conformers) to consider

wei22:11:26

any best practices for ns qualifying keywords that come out of a db?

wei22:11:23

in particular is there a function for adding a namespace to all bare keys in a map

rickmoynihan22:11:35

One observation whilst playing with spec is that it seems to be “static” by design, in that it doesn’t seem to encourage or allow you to programmatically build/modify and refine specs. For example one thing I used to do with schema (especially in tests) was define a generic schema for something and then in specific tests where I want to test something more specifically e.g. the presence of a specific test value in the output, I’d simply assoc a new specific value into the schema, and validate against that. Is this a fair point in understanding the pro’s and con’s of spec vs other schema libraries?

rickmoynihan22:11:40

(I should say it seems totally fair to me that spec trades off dynamism for something more static and comprehensible)

hiredman22:11:06

hard to say

hiredman22:11:19

the combinators are different

hiredman22:11:33

instead of associng in, you might s/and a new s/keys spec

hiredman22:11:54

I think there is a bias in spec towards naming things globally, vs some kind of local names or anonymous things

hiredman22:11:31

I guess I'd say, I don't think spec is particularly static, but the bias towards global names can make it feel that way some times. And the bias is just a bias, you can do that kind of stuff, you might just have to venture off the beaten path of what is provided in the box

rickmoynihan22:11:11

hiredman: yeah I think you’re right

aengelberg23:11:22

How can you define mutually recursive specs?

zane23:11:45

I don't remember having to do anything special.

Alex Miller (Clojure team)23:11:12

Just refer to them by (qualified keyword) name

Alex Miller (Clojure team)23:11:34

They delay evaluation so should just work