clojure-spec

slipset 2022-01-10T20:15:52.002Z

We were discussing at work today, and this cropped up:

ardoq.core> (spec/def :foo/foo string?)
;; => :foo/foo
ardoq.core> (spec/def :foo/bar int?)
;; => :foo/bar
ardoq.core> (spec/def ::test (spec/keys :req [:foo/foo]))
;; => :ardoq.core/test
ardoq.core> (spec/valid? ::test {:foo/foo "foo" :foo/bar 1})
;; => true
ardoq.core> (spec/valid? ::test {:foo/foo "foo" :foo/bar "1"})
;; => false
In the last example, :foo/bar is not mentioned in ::test but seems to still be checked. What am I not seeing?

mpenet 2022-01-10T20:19:44.003200Z

s/keys will cause all namespace qualified keys to be checked

slipset 2022-01-10T20:23:48.005900Z

Right, it’s there in the docstring: > In addition, the values of all namespace-qualified keys will be validated > (and possibly destructured) by any registered specs. TIL.

slipset 2022-01-10T20:26:53.007300Z

Which still is a bit strange since then:

ardoq.core> (s/def :foo/foo string?)
;; => :foo/foo
ardoq.core> (s/def :foo/bar int?)
;; => :foo/bar
ardoq.core> (s/def ::test (s/keys :req []))
;; => :ardoq.core/test
ardoq.core> (s/valid? ::test {:foo/foo "foo" :foo/bar "1"})
;; => false
ardoq.core> 
Which makes you wonder why even bother with :req ?

mpenet 2022-01-10T20:28:14.008900Z

You still need to be able to express what key set is required

mpenet 2022-01-10T20:28:35.009600Z

I guess for opt it's debatable. It's mostly for gen there

slipset 2022-01-10T20:29:08.009800Z

True

mpenet 2022-01-10T20:30:48.012Z

Also if you have a ns qualified key that points to a value that does not conform to the spec with the same key, no matter where, it's likely a smell. Integrant pushes toward this for instance, I am not a fan of that part of the lib.

Alex Miller (Clojure team) 2022-01-10T20:32:10.013400Z

opt is used for gen