Fork me on GitHub

Is there a way to make fn spec that allows fn to throw exceptions? I want to express a contract "this function returns any value and can even throw"


IIRC, no.


This has encouraged me to spec out some of my functions to return values that indicate success or failure. Often they’re :cognitect.anomalies/anomaly values. I’m pretty happy with this approach. It makes the functions more testable, I think. And by speccing out the error values you get the property testing to extend to error cases as well.


Yeah, but I want to document that I allow user-provided callback to throw an exception. It’s like a promise “it’s okay to fail”…


Yeah, makes sense, reasonable. I just think that’s out of scope for spec.


If I were to speculate the thinking behind that call, I’d guess that it’s an example of the position that exceptions should be used in truly exceptional cases — cases that are hard to predict and handle — and can thus be thrown anywhere, at any time. (That’s a reductive summary missing much nuance but I hope potentially slightly useful.) Just speculation though, I could easily be mistaken.


This might be a little silly, but in some cases I’ve written functions that catch Exceptions and then return them as values! e.g.

(s/fdef check-render-result
  :args (s/cat :result (s/or :success ::r/success-result
                             :failure ::r/failure-result)
               :path   ::fs/file-path-str)
  :ret  (s/or :success nil?
              :failure (partial instance? Exception)))

Alex Miller (Clojure team)14:04:25

function specs document non-exceptional use

Alex Miller (Clojure team)14:04:47

so they don't include any way to talk about exceptions




I am trying to spec the requests and responses to an API, but am running into issues with namespace collisions.

(ns my-app.validate.endpoint-a)

(s/def :ok-response/status #{200})
(s/def :ok-response/body ...)

(s/def ::ok-response (s/keys :req-un [:ok-response/status

(s/def :created-response/status #{201})
(s/def :created-response/body ...)

(s/def ::created-response (s/keys :req-un [:created-response/status

(s/def ::response (s/or :ok ::ok-response
                        :created ::created-response))
The problem comes when I add validation for endpoint-b which will also have an :ok-response/body which will be different than that for endpoint-a. I am already encoding the type of response (`ok-response` vs. created-response ) in the kw namespace due to s/keys mandating that the kw name matches the key in the map being spec'd. I can continue to encode further dimensions (endpoint, method) into the namespace to avoid these collisions, but it quickly gets unwieldy:
(s/def :get-endpoint-a-ok-response/body ...)
Am I overlooking an idiomatic way of handling this problem? I'd love to see something like
(s/def ::ok-response-body ...)

(s/def ::ok-response (s/named-keys :req {:status #{200}
                                         :body   ::ok-response-body}))


Note: s/named-keys above could also address support for string keys


Spec 2 will provide that functionality @jmromrell if I’m understanding correctly what you are asking.


That's great. The inflexibility of s/keys has been a pain point for me multiple times.


But it sounds like you might also want to look at multi-spec?


I'll look into it. Thank you!