Fork me on GitHub
Martynas Maciulevičius07:07:18

Hey. Is there a good way to spec an atom that has a list of functions? 😄 Is there at least a way to spec an atom?


Any predicate can be used as a spec



(s/def ::fns (s/coll-of ifn?))
(s/def ::my-atom 
  (s/and (s/conformer 
           #(if (instance? clojure.lang.Atom %) 

(s/valid? ::my-atom (atom [dec identity inc])) ; => true


maybe this use of conformer is not idiomatic. tbh I’m not sure what’s an idiomatic use of conformer


I think this is not idiomatic, because spec is a “library [that] specifies the structure of data” (as per, and atoms are state, not data


so maybe you could consider not speccing atoms? 🙂

Martynas Maciulevičius07:07:11

I think I'll not do it.

Colin P. Hill13:07:42

Atoms are stateful containers of data. It often makes a lot of sense to spec atoms, especially if they're a highly structured central data store for your application – similar to having a formal schema for a database. The atom function even has an option for including a validator, which could be built on spec (though be mindful of performance and consider making it no-op in prod).

Colin P. Hill13:07:59

A naive (in the sense that it doesn't check function signatures) spec for a list of functions might be (s/* ifn?)

Eric Dvorsak14:07:05

In the core.specs, isn't ::map-special-bindings always going to be a subset of ::map-bindings? how would ::map-special-bindings spec ever be used given that it's only part of :map-binding-form spec which is defined as (s/def ::map-binding-form (s/merge ::map-bindings ::map-special-binding))

kwladyka14:07:42 here is use case showing the difference (s/def ::created ::instant) vs (s/def ::created (s/and ::instant))


I don’t know the exact code which you are asking, but I know the difference between this too

Eric Dvorsak14:07:38

I'm not sure I understand your answer, do you mean the intention might just be to produce better error messages?


:via [:foo/created], vs :via [:foo/created :foo/instant],


I mean without s/and you miss the information about the full path, because it cut corners to make path simpler


s/and keep full path and this is ONLY ONE WAY to get this information

Eric Dvorsak14:07:24

ok, although there's no and involved in the code I linked to (clojure.core.spec.alpha), it's a merge of a spec map-bindings with another map-special-binding after double checking it seems to me like the only point of map-special-binding is to keep the map-binding-form spec open to new keywords


I don’t know this part of the code, so I can’t really give you deeper answers