I used the last days to dig deeper into clojure.spec in Clojure and ClojureScript.
Until now I find it most useful, to use specs as guards in :pre
I think the idea is that you use spec/instrument
to validate function input and output rather than pre and post conditions.
There's a good example toward the bottom of this blog post: http://gigasquidsoftware.com/blog/2016/05/29/one-fish-spec-fish/ . Quick summary: you can define a spec for a function, including both input and return values using the :args and :ret keys (thus replacing both pre and post conditions), with spec/fdef
, instrument it, and you get output similar to using explain
when it fails to meet spec.
Minimal example derived from that link:
(spec/fdef your-func
:args even?
:ret string?)
(spec/instrument #'your-func)
And that's equivalent to putting a precondition that the function has an integer argument and a postcondition that it returns a string. Except you get much more useful errors, just like you're looking for.
More details in the official guide: https://clojure.org/guides/spec ---see under the heading "Spec'ing functions".