I am having a problem understanding how these functions update the underlying ref, atom etc.
The docs say:
(apply f current-value-of-identity args)
(def one (atom 0))
(swap! one inc) ;; => 1
So I am wondering how it got “expanded” to the apply form. It’s not mentioned what exactly ‘args’ in the apply form is. Is it a sequence of arguments or are these separate values?
Was it “expanded” to:
(apply inc 0) ; obviously this wouldnt work, so that leaves only one possibility
(apply inc 0 '())
(swap! one + 1 2 3) ;; #=> 7
Was it:
(apply + 1 1 2 3 '()) ;or
(apply + 1 [1 2 3])
(def two (atom []))
(swap! two conj 10 20) ;; #=> [10 20]
Was it:
(apply conj [] [10 20]) ;or
(apply conj [] 10 20 '())
The passage you quoted from
swap!‘s docstring means that what happens is the equivalent of swapping in a new value for the Atom obtained from the old one with(apply f old-value args), whereargsis a seq of all additional arguments passed toswap!.What actually happens is different, but that’s just an implementation detail. For the sake of curiosity: Atoms have a Java method called
swap, which is overloaded to take from one to four arguments. The first one is always anIFn(thefpassed toswap!); the second and third, in present, are the first two extra arguments to thatIFn; the fourth, if present, is anISeqof extra arguments beyond the first two.applyis never involved and the fixed arity cases don’t even call theIFn‘sapplyTomethod (they just useinvoke). This improves performance in the common case where not too many extra arguments are passed toswap!.