clojure-spec

About: http://clojure.org/about/spec Guide: http://clojure.org/guides/spec API: https://clojure.github.io/spec.alpha/clojure.spec.alpha-api.html
sam 2021-04-15T05:38:32.063600Z

I could use some guidance on using clojure.spec to validate input arguments to a function. Here’s some context: • I am debating instrumenting with fdef vs. using :pre and :post conditions. • The function is internal to the app and the argument values are completely under the control of the programmer (i.e. there is no validation of external data going on). I was initially leaning toward instrumenting with fdef because I see this as a check for program correctness rather input validation. It should be safe to turn this check off in production with no change in behavior. But I want the instrumentation to be turned on by default during development and turned off by default in production. I can imagine ways to achieve that, but the fact that I couldn’t find any mention of a typical pattern for doing that (e.g. my understanding is that assert is set up to be easily enabled/disabled in a blanket manner) made me think I might be missing something.

vemv 2021-04-15T10:21:26.064100Z

> I was initially leaning toward instrumenting with fdef because I see this as a check for program correctness rather input validation. what's this? (I can interpret it in two different ways)

sam 2021-04-15T14:37:19.066500Z

Yeah, that’s fair. this = “this solution I’m designing”, not this = “instrumenting with fdef”.

👍 1
vemv 2021-04-15T14:52:00.067Z

If ease of turning on/off is the main concern, perhaps I'd go for fdef because it's the default choice, and toggling it globally, and both for inputs and outputs seems relatively easy with https://github.com/jeaye/orchestra There are reasons beyond toggling ease why some people might prefer assert to instrumentation. https://github.com/fulcrologic/guardrails or https://github.com/nedap/speced.def (disclaimer: I authored it) and probably a couple more libraries favor it. There's no fixed truth in the topic, but in absence of other concerns I'd probably 'start small'.

sam 2021-04-15T14:59:46.067700Z

@vemv Thanks a ton! I need to digest this more and check out orchestra. Off the top of my head, my only concern is that I usually like to be a little wary about adding new dependencies if I don’t have to.

sam 2021-04-15T05:44:46.063800Z

Another thing I should mention is that I have no intention of ever testing this function with generative tests. It’s not a good fit for generative testing.

alexmiller 2021-04-15T12:38:38.065600Z

Are you talking about clojure.core/assert or s/assert? Seems like the latter would be good here

sam 2021-04-15T14:48:17.066800Z

Thanks! Somehow I missed s/assert , I think you’re right. Maybe s/assert in a :pre condition…

alexmiller 2021-04-15T14:53:05.067200Z

I'd put it in the mainline

alexmiller 2021-04-15T14:54:38.067400Z

s/assert in mainline code is designed so that it can be compiled completely out of the program via https://clojure.github.io/spec.alpha/clojure.spec.alpha-api.html#clojure.spec.alpha/*compile-asserts*

sam 2021-04-15T15:00:49.067900Z

Okay, thank you! I really appreciate the guidance.

Franco Gasperino 2021-04-15T22:22:28.071400Z

Hello. Where i have several defined and registered predicates, can i compose them in this state?

;; contrived example
(s/def ::string-starts-with-an-a? (s/and string? #(string/starts-with? % "a")))
(s/def ::not-an-apple? #(not= "apple" %))
(s/def ::starts-with-an-a-but-not-an-apple? (s/and ::string-starts-with-an-a? ::not-an-apple?))

Franco Gasperino 2021-04-15T22:25:20.072100Z

predicate composing after registration

Franco Gasperino 2021-04-15T22:26:37.072800Z

disregard the above. my forms had not been evaluated, thus the error received was entirely my doing