 Clojure's reference types are its only native mutable data structures. The four reference types are called refs, atoms, agents, and vars. As already explained, vars are the objects mapped to symbols and namespaces, and their intended purpose is to hold the top-level code objects and global variables of our programs. Vars are created and assign new values with a def form and its variance. When we define a top-level function, we shouldn't reassign its var in the normal course of business. However, replacing existing functions is useful when debugging or live-patching a system. When we use vars as global variables in contrast, we of course def these vars' new values in the normal course of the program. Vars are Clojure's simplest, most straightforward way to represent mutable state. The problem with defing vars this way, however, is that it does nothing to mitigate the ills of mutable state. As separate parts of code and separate threads of execution all read and write your mutable vars, they can easily get each other confused. That's where the other three reference types come in. Refs, atoms, and agents, unlike vars, impose a degree of discipline in how you update the mutable state which they hold. Before delving into these other reference types, one thing we haven't mentioned yet about vars is that they can be marked as dynamic with metadata. By convention, dynamic vars are mapped to symbols that begin and end with an asterisk. Here, we're defing a dynamic var mapped to the symbol asterisk x asterisk. What a dynamic var does is allow us to apply temporary thread local bindings to it with the binding macro. The provided value is thread local bound to the var for the duration of the body. By thread local, we mean that the assignment is only seen in the thread that executes the binding form. All other threads see the normal value of the var, its so-called root binding. Once the binding form returns, the thread local binding is discarded, and so this thread will see the root binding. Consider this example. Here, the var mapped to x holds the value 3, and so when the foo function is called, it would normally print 3. In our binding form, however, we give x the thread local binding value 5, and so the call to foo in the binding form body prints 5. If at the same time another thread happens to use the var mapped to x, while the binding form is executed, that other thread would see the root binding 3, or possibly its own thread local binding if it happens to itself reassign x in the binding form. After the binding form returns, the root binding is once again used in this thread, so the last call to foo prints 3. While occasionally useful, you should be very cautious of using dynamic vars in the binding form. Though the effect of a binding form is temporary and neatly confined to one thread, it still does mutate state that may be visible to disparate parts of code, which always has a potential to create hard to fix bugs. Let's cover what atoms, agents, and roughs have in common. Like vars, these other reference types can be thought of like collections that hold a single value. Here we have an atom with a value 3, an agent with a value 9, and a rough with the initial value negative 7. The D rough function returns the currently held value of all these types. Where the three types differ is in how we change their held values. For atoms we use the function swap, for agents we use the function sendoff, and for roughs we use the function alter. All three of these functions expect the same arguments, first the reference, then a function, then zero or more arguments for that function. Here in this call to swap, we're updating the value of the atom A with the plus function and the arguments 4 and 1. The plus function is invoked with first the current value of the atom, 3, then the arguments 4 and 1, so it returns 8, 3 plus 4 plus 1, and that is the new value of the atom. For reasons we'll explain shortly, the alter function throws an exception if not invoked inside the body of a call to the doosync macro. What all three of these functions do is give their respective references a new value from what is returned by the supplied function when invoked with the references current value as the first argument and the supplied arguments as the remaining values. For example, swap here invokes the plus function with the arguments 3, 4, and 1, so the atom gets the new value 8. The common pattern here is that atoms, agents, and roughs have their values updated by provided functions, not by simply providing the new value. The reason for this is that the update is guaranteed to be atomic. If another thread changes the same references value during the call to the supplied function, or in the case of roughs during the body of the doosync, then the function or the doosync body will start over with a new value of the reference. For example, if during our call to swap, another thread had changed the atom's value to 23, then the swap would run the function again, this time with the value 23 is the first argument. If the atom's value is changed again before the swap completes, it runs the function once more. This happens indefinitely until the swap runs the function without another thread interfering, only then is the return value of the function assigned to the atom. What roughs can offer that atoms do not is consistency between multiple references. An atom swap only reruns when the atom itself is modified by another thread. A doosync in contrast reruns when any rough that is read or written in its body is modified by another thread. This happens indefinitely until the doosync makes a complete run in which none of the rough values get modified in any other thread. Here, if the roughs of either x or y get modified by some other thread during this doosync body, the doosync will restart with the new values of the roughs. Agents differ from atoms in that whereas the swap function immediately runs its supplied function and returns the new value of the atom, the sendoff function runs its supplied function asynchronously in a thread pool and always immediately returns the agent itself. Because the updates of a single agent are always performed in the same thread, they cannot possibly overlap and so never have to be rerun. Effectively, agents are an optimized alternative to atoms. Because their updates run in a separate thread, the updates won't block other work from getting done and because their updates never rerun, they don't do wasted work. The big catch of course is that because an agent's updates run asynchronously, they're only an acceptable choice when we don't need the updates to happen immediately. Also understand that when multiple threads send off updates to the same agent, the updates will be performed in an interleaved order, so we generally shouldn't be particular about an agent's order of updates. If you de-ref an agent, it will return the current value whether or not updates on the agent are still pending. If this is unacceptable, we can call the await function which blocks the current thread until all updates initiated on an agent from the current thread complete. So here this first call to de-ref, we can't be certain if it's going to return 9 or 14 because we can't know if the send off has completed yet. The second call to de-ref though comes after a call to await, and so we can be certain that it will return 14 and not 9. Though actually it is possible it might return something other than 14 if some other thread has called a send off on this agent which happens to have completed by this call to de-ref. So we can't say for certain the value will be 14, but we can be certain that the send off we called here in this thread has completed. If you find that you always use await after updating an agent, you probably should just use an atom instead. In fact, agents are most appropriate in the cases where we don't need await at all.