Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Clojure.Spec a reference type (like atom)?

I wonder how I would spec a function, that has a parameter, that hold a map in an atom.

(defn do-something [a]
  (prn (vals @a)))

This those obviously not work:

(s/fdef do-something
  :args (s/cat :a map?))

How would I spec that a is a reference to map?

like image 913
DiegoFrings Avatar asked Jun 22 '16 15:06

DiegoFrings


People also ask

What is atom in Clojure?

Atoms are a data type in Clojure that provide a way to manage shared, synchronous, independent state. An atom is just like any reference type in any other programming language. The primary use of an atom is to hold Clojure's immutable datastructures. The value held by an atom is changed with the swap!

What is spec in Clojure?

spec is a Clojure library to describe the structure of data and functions. Specs can be used to validate data, conform (destructure) data, explain invalid data, generate examples that conform to the specs, and automatically use generative testing to test functions.


2 Answers

Don't. clojure.spec is about specifying the structure of data and atoms are state, not data. Not every function necessarily needs to have (or check) a spec.

My general advice for dealing with stateful data is to:

  • Define your data
  • Define pure functions to that take and return your data
  • Create specs for those data functions
  • Manipulate atoms using only those pure functions in as few places as possible

With some care, you can often reduce the number of functions that take or return atoms to 0 (by closing over the atom in the place where it's managed), which is imho a worthy goal.

like image 61
Alex Miller Avatar answered Nov 15 '22 05:11

Alex Miller


You don't. For one reason, it wouldn't be thread-safe. If you did somehow spec that a atom contained a map, it could change to an integer in the time it takes you to check the atom, and continue with your function.

One option, however, is to provide a validator to the atom. You could easily use partial to do this: (set-validator! my-atom (partial s/valid? :my-spec)). Now the atom will fail to update unless the value conforms to :my-spec.

Another option is to add validation logic to all the functions that update the atom. Which of these two approaches works best depends on the application.

like image 43
Timothy Baldridge Avatar answered Nov 15 '22 05:11

Timothy Baldridge