Must be called in a transaction. Sets the in-transaction-value of
ref to:
(apply fun in-transaction-value-of-ref args)
and returns the in-transaction-value of ref.
;; alter is a way to change the value of a reference.
;; Here we're defining a ref named 'names' and setting its value to
;; an empty vector.
user=> (def names (ref []))
#'user/names
;; A function to add a name to the vector (notice the meat's wrapped
;; in a dosync
user=> (defn add-name [name]
(dosync
(alter names conj name)))
#'user/add-name
user=> (add-name "zack")
["zack"]
user=> (add-name "shelley")
["zack" "shelley"]
;; Notice that the var 'names' points to the reference that we created
user=> (println names)
#<Ref@658ba380: [zack shelley]>
;; To get the actual value of the ref, you use the '@' symbol, or deref
user=> (println @names)
[zack shelley]
user=> (println (deref names))
[zack shelley]
(defn alter
"Must be called in a transaction. Sets the in-transaction-value of
ref to:
(apply fun in-transaction-value-of-ref args)
and returns the in-transaction-value of ref."
{:added "1.0"
:static true}
[^clojure.lang.Ref ref fun & args]
(. ref (alter fun args)))
Comments top
2 comment(s) for alter.
I was fooling around with how exactly ref works with maps. Since the example here uses a vector, I thought maybe some of you might want to see a short example using a map.
In an aggregator I'm working on, I want to keep a record of how many sources and how many articles I've aggregated. Instead of using an atom for each, I'll reference a map called "counts." Here's a simple little function that increments and returns the new value of the counter stored in the map:
(def counts (ref {:articles 0 :sources 0})) (defn inc-ref [ref type] "increment a map value with key type stored in ref" (dosync (alter ref assoc type (inc (type @ref))) (type @ref))) user> (inc-ref counts :sources) =>1 user> counts =>{:articles 0, :sources 1}and if you wanted to be able to add counters dynamically (one of the advantages of using a map in this context) you could redefine the function employ an optional argument, which if present instructs the function to create a new key-value pair using the name and initial value provided:
(defn inc-ref [ref type & [init-value]] (if init-value (dosync (alter ref assoc type init-value) (type @ref)) (dosync (alter ref assoc type (inc (name @ref))) (type @ref)))) user> (inc-ref counts :articles) =>1 user> (inc-ref counts :magazines 1) =>1 user> (:magazines @counts) =>1(def counts (ref {:articles 0 :sources 0})) (defn inc-ref [ref type] "increment a map value with key type stored in ref" (dosync (alter ref assoc type (inc (type @ref))) (type @ref))) user> (inc-ref counts :sources) =>1 user> counts =>{:articles 0, :sources 1}and if you wanted to be able to add counters dynamically (one of the advantages of using a map in this context) you could redefine the function employ an optional argument, which if present instructs the function to create a new key-value pair using the name and initial value provided:(defn inc-ref [ref type & [init-value]] (if init-value (dosync (alter ref assoc type init-value) (type @ref)) (dosync (alter ref assoc type (inc (name @ref))) (type @ref)))) user> (inc-ref counts :articles) =>1 user> (inc-ref counts :magazines 1) =>1 user> (:magazines @counts) =>1In the previous example at row 07 has a reference to 'name @ref':
maybe is incorrect and the correct mode is: