Where should a spec be defined relative to a function

(written by lawrence krubner, however indented passages are often quotes). You can contact lawrence at: lawrence@krubner.com

This is an interesting conversation on the Clojure mailist, and this question is relevant for more than just Clojure. It touches on the main question of language design.

Didier feels it should be possible to define the spec with the function, and this functionality should be added to the Clojure core, so that this would become idiomatic Clojure:

Gary Trakhman argues that this would make the core “defn” macro too slow, and therefore everything about spec should be left to the application level architects:

Defn right now is primitive enough to be fast and powerful enough for large programs. There are many general and competing things a developer might want to be available in a more powerful or opinionated defn, but I think we’d agree the benefit of what you propose scales as a convention across a larger codebase and so do other general defn wrappers. I can think of a few other examples like this, how about plumatic’s defnk graph function macro? How about core.match pattern-matching with the ‘defun’ project? How about the schema s/defn? How would someone combine them when macros generally don’t compose too well?

I think that sort of thing should be possible, but too opinionated for how ‘core’ clojure.spec is intended to be. Decisions like that are for application architectures.

Didier responds by saying they will do some experiments of their own. They also suggest that leaving “defn” too general raises the Lisp Curse:

I take from this that there’s nothing terribly wrong if I implemented a macro of my own, but I understand that for the core offering, its more flexible to standardize around function specs to be separate.

I’m sure I can get creative about where to put the fn spec :p. I was thinking the attr-map could optionally be a spec instead, or contain an :fn key if you want both.

Having said that, it does seem to me like a lot of people are struggling with “Where do I put my function specs?”, me included. And from my research, most people like to put them right above the function, or right below. So I thought that for most use cases, where you don’t want to spec an existing API, this would make it unambiguous. And I’ve also found that a lot of people actually leave their specs in production, with some even keeping instrumentation on fully. It seems that failing fast is often prioritized over the small performance overhead.

Anyways, I’ll give it a shot and experiment, see how it goes.

I think that sort of thing should be possible, but too opinionated for how ‘core’ clojure.spec is intended to be. Decisions like that are for application architectures.

I think yes, to some extent, but we should also be careful about the Lisp curse. If core has too little opinion, each Clojure code base will be like its own dialect full of secret functions and macros.

I think the Clojure team made the right decision, but I could see arguing this both ways.

Source