background preloader

State

Facebook Twitter

Clojure differences between Ref, Var, Agent, Atom, with examples. Clojure differences between Ref, Var, Agent, Atom, with examples. Clojure: State Management. Those unfamiliar with Clojure are often interested in how you manage changing state within your applications. If you've heard a few things about Clojure but haven't really looked at it, I wouldn't be surprised if you thought it was impossible to write a "real" application with Clojure since "everything is immutable".

I've even heard a developer that I respect make the mistake of saying: we're not going to use Clojure because it doesn't handle state well. Clearly, state management in Clojure is greatly misunderstood. I actually had a hard time not calling this blog entry "Clojure, it's about state". I think state shapes Clojure more than any other influence; it's the core of the language (as far as I can tell). Rich Hickey has clearly spent a lot of time thinking about state - there's an essay at which describes common problems with a traditional approach to state management and Clojure's solutions.

At the end of Rich's essay he says: but, I digress. State. Fast Track Clojure: Lesson 7 - What? No Variables in Clojure? If you noticed by now, we have gone through six lessons and haven't yet created a variable. At least not explicitly. We did create some lexically scoped variables that were created implicitly as function arguments, or bindings to the "loop" and "reduce" functions we saw. It is highly unlikely that you would go through six lessons in any programming language (non Lisp) and not create a variable. There are global variables in Clojure, which you create with the "def" function. And the "let" function which allows you to create lexically scoped variables. However the fact that we haven't used them so far is a good thing.

Also in Clojure you can get away with not creating variables because of the usage of higher order functions. Clojure variables are immutable. Let us get on with improving our web server. (create-server 8080 (fn [in out] (binding [ *in* (BufferedReader. Run the above code and browse to localhost:8080. The let function takes an array of bindings. Vars. Clojure - is this an appropriate use of an atom? Agents. Like Refs, Agents provide shared access to mutable state. Where Refs support coordinated, synchronous change of multiple locations, Agents provide independent, asynchronous change of individual locations. Agents are bound to a single storage location for their lifetime, and only allow mutation of that location (to a new state) to occur as a result of an action. Actions are functions (with, optionally, additional arguments) that are asynchronously applied to an Agent's state and whose return value becomes the Agent's new state.

Because actions are functions they can also be multimethods and therefore actions are potentially polymorphic. Also, because the set of functions is open, the set of actions supported by an Agent is also open, a sharp contrast to pattern matching message handling loops provided by some other languages. Example (defn relay [x i] (when (:next x) (send (:next x) relay i)) (when (and (zero? Related functions. Refs. While Vars ensure safe use of mutable storage locations via thread isolation, transactional references (Refs) ensure safe shared use of mutable storage locations via a software transactional memory (STM) system.

Refs are bound to a single storage location for their lifetime, and only allow mutation of that location to occur within a transaction. Clojure transactions should be easy to understand if you've ever used database transactions - they ensure that all actions on Refs are atomic, consistent, and isolated. Atomic means that every change to Refs made within a transaction occurs or none do. Consistent means that each new value can be checked with a validator function before allowing the transaction to commit. Example Related functions Create a Ref: ref Examine a Ref: deref(see also the @ reader macro) Transaction macros: dosyncio! Clojure: State Management. Clojure: State Management. Are We There Yet? Clojure differences between Ref, Var, Agent, Atom, with examples. Clojure from the ground up: state. Previously: Macros.

Most programs encompass change. People grow up, leave town, fall in love, and take new names. Engines burn through fuel while their parts wear out, and new ones are swapped in. Forests burn down and their logs become nurseries for new trees. Identity is a skein we lay across the world of immutable facts; a single entity which encompasses change. In this chapter, we’ll move from immutable references to complex concurrent transactions.

Immutability The references we’ve used in let bindings and function arguments are immutable: they never change. user=> (let [x 1] (prn (inc x)) (prn (inc x)))22 The expression (inc x) did not alter x: x remained 1. User=> (let [x [1 2]] (prn (conj x :a)) (prn (conj x :b)))[1 2 :a][1 2 :b] Immutability also extends to let bindings, function arguments, and other symbols. The present function creates a new function. This is called closing over the gift variable; the inner function is sometimes called a closure. Delays Futures Promises Vars Atoms.