This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-12-08
Channels
- # adventofcode (60)
- # announcements (3)
- # babashka (31)
- # beginners (5)
- # boot (1)
- # calva (13)
- # cider (9)
- # clj-kondo (1)
- # clojure (135)
- # clojure-italy (18)
- # clojure-nl (18)
- # clojure-spec (21)
- # clojure-uk (11)
- # clojuredesign-podcast (1)
- # clojurescript (47)
- # core-async (14)
- # emacs (7)
- # euroclojure (4)
- # fulcro (3)
- # graalvm (19)
- # off-topic (22)
- # reagent (29)
- # shadow-cljs (25)
- # vim (3)
Is this supposed to work in spec 2?
(s/def ::some-keyword ::some-other-keyword)
When I try to validate against ::some-keyword
I get this exception:
java.lang.IllegalArgumentException: No implementation of method: :conform* of protocol: #'clojure.spec-alpha2.protocols/Spec found for class: clojure.lang.Keyword
I can fix the symptoms by doing this instead of s/def
, but the fact that I have to do a special dance makes me suspect that I might be working against the tool's grain
(s/register ::some-keyword (s/resolve-spec ::some-other-keyword))
I get that spec2 is stricter than spec1 in terms of separating symbolic specs from spec objects.
From the documentation (https://github.com/clojure/spec-alpha2/wiki/Differences-from-spec.alpha) (emphasis mine)
> s/def
is a helpful wrapper macro for s/register
that understands how to interpret all kinds of symbolic specs (not just spec forms), including symbols and sets, which will be wrapped in the helper s/spec
spec op.
I was hoping that ::some-other-keyword
would qualify as a symbolic spec, but maybe not.
I believe aliased Specs are supposed to work but there are situations where you can forward reference in Spec 1 but you cannot yet forward reference in Spec 2.
I assume ::some-other-keyword
is defined after ::some-keyword
here?
Actually, it's imported from another ns in my real code, shouldn't have tried to simplify that away
user=> (require '[clojure.spec-alpha2 :as s])
nil
user=> (s/def ::one pos-int?)
:user/one
user=> (s/def ::two ::one)
:user/two
user=> (s/valid? ::two -1)
false
user=> (s/valid? ::two 1)
true
user=>
In that simple case, it does let you forward reference FYI -- I tried it in a fresh REPL session with the defs of ::one
and ::two
swapped and it still worked.
Interesting. Thank you for the handholding 😊, will try to figure out what I'm doing differently and report back
With the caveat, again, that there are numerous bugs in Spec2 still at this point. And it sounds like function specs will change dramatically before they're done, according to Alex's latest blog point (and s/and
may become non-flowing -- which would be another departure from Spec1). While I was working against the Spec2 branch for a while, things would break between various updates on master, sometimes intentionally but often unintentionally. It's very much a moving target right now.
I had hoped to migrate our (large) codebase from Spec1 to Spec2 but, in reality, I think we're "stuck" with Spec1 in our existing code at this point and we'll just adopt Spec2 for new code (depending on how Spec1 and Spec2 interop -- because they don't, right now).
Eventually, we'll convert everything over but I suspect we'll do it piecemeal over time.
Maybe I should just switch back to spec 1, and follow the advice above (<https://clojurians.slack.com/archives/C1B1BB2Q3/p1575541261064300>) to make all my specs :opt
rather than :req
, merging in :req
at the last minute to emulate schema
and select
.
> make all my specs :opt rather than :req, merging in :req at the last minute to emulate schema and select. I hadn’t seen the discussion of that above, but that’s pretty much what I’ve come to independently for a large-ish set of domain specs I’ve been working on. Seems to be a decent approach.
Along with a couple of helper functions to eg build a selection from a schema less verbosely by passing in the base schema and the list of attributes that should be required (in the simple cases), and by passing in the base schema and a full tree of requiredness (for complex cases).