did, they'd be different values) • e.g., 72, {–, ‖, —, ―}, "cat", [2, 3, 5, 7] • An Identity is an entity that is associated with different values over time • State is a value at a point in time • Identities give us continuity across state changes
• Assumes observing and changing data happens immediately (that computation halts until an operation is completed) • In OOP, Complects Identity and State • No way to obtain state independent of identity without copying • Objects not treated as values • Unsustainable single-threaded premise
that the world stops as data is observed or mutated by multiple participants, which is both expensive and complex: • Requires coordination with mutexes/locks • Changes must be propagated to shared memory to be visible to other threads • Writers must block readers / readers must block writers to observe and operate on stable state • Complexity rapidly increases with more threads • Dead-lock, Live-lock, Race-conditions
• An Identity's state at any point in time is an immutable value • Values can always be observed and new values calculated from old values without coordination • Values will never change "in hand" • Values can be safely shared between threads
references to immutable values • Dereferencing a reference type gives you its (immutable) value • Changes to an identity's state are controlled/coordinated by the system
else?) conditional, yields `then` or `else` (do exprs*) evaluate expressions, return last (let [bindings* ] exprs*) lexical context (quote form) yields an unevaluated form (unquote form) unquotes a quoted form (var symbol) the var object named by a symbol (fn name? ([params*] cond-map? exprs*) +) defines a function (loop [bindings* ] exprs*) like let, but provides a recursion target (recur exprs*) evaluates expressions and rebinds at recur point (throw expr) evaluates expr and throws result (try expr* catch-clause* finally- clause?) try/catch/finally semantics . new set! javascript interop
that commute • Synchronous, independent updates • State changes by applying pure functions to the current state's value to produce the next state's value • Operations: • swap!, reset!, compare-and-set!, deref, add-watch, set-validator!
(apply f current-value-of-atom args). Returns the value that was swapped in. (swap! a f) (swap! a f & args) (def mycounter (atom 0)) (swap! mycounter inc) => 1 (def names (atom [])) (swap names conj "John") => ["John"]
reactively, serially • Ideal for guarding a contested resource • Asynchronous, independent updates • State changes by asynchronously applying pure functions to the current state's value to produce the next state's value • Agents update are applied in the order received by a thread from the agent thread pool • Operations: • send, send-off, deref, reset-agent, agent-error, shutdown-agents, add-watch, set- validator!
immediately. Subsequently, in a thread from a thread pool, the state of the agent will be set to the value of: (apply action-fn state-of-agent args) (send a f & args) (defn log-msg [msg user] {:timestamp (java.util.Date.) :msg msg :user user}) (def command-log (agent [])) (send command-log conj (log-msg "Fire ze missiles!" "Joe")) @command-log => [{:timestamp #inst"2016-02-15T01:23:49.745-00:00", :msg "Fire ze missiles!", :user "Joe"}]
Ideal for coordinating changes to multiple states • Updates in transactions; Transactions "snapshot" of data + in-transaction-value • actions on refs are atomic, consistent, and isolated from other transactions • Software Transactional memory implements a form of MVCC with adaptive history queues for snapshot isolation • Operations: • alter, ref-set, commute, ensure
of code communicating over "channels" • Channels are queues that can be combined, split, filtered, mapped over, etc. • Channels can exert "backpressure" and have different kinds of buffers of different sizes (sliding, dropping, etc.) • async blocks execute in a thread pool • Think Go, but richer API and works in ClojureScript (in browsers!)
nil values are not allowed. Will block if no buffer space is available. Returns nil. (<!! c) takes a val from a channel. Will return nil if closed. Will block if nothing is available.