Comparing the source code of clojure.lang.Ref and clojure.lang.Atom, I see that they both inherit from clojure.lang.ARef.
In clojure.lang.ARef there is a function notifyWatches which lets all the watch function know that a change has been made.
the swap! and reset! functions in clojure.lang.Atom calls notifyWatches in its implementation.
eg.
public Object swap(IFn f) {
for(; ;)
{
Object v = deref();
Object newv = f.invoke(v);
validate(newv);
if(state.compareAndSet(v, newv))
{
notifyWatches(v, newv);
return newv;
}
}
}
However, when I do a search for notifyWatches in clojure.lang.Ref, it comes up with nothing. The alter function looks like this.
public Object alter(IFn fn, ISeq args) {
LockingTransaction t = LockingTransaction.getEx();
return t.doSet(this, fn.applyTo(RT.cons(t.doGet(this), args)));
}
How do all the watch functions of a ref get notified if none of the methods are calling notifyWatches?
The call to
notifyWatchesyou are looking for occurs in therunmethod of theLockingTransactionclass.Changes to refs happen in transactions. Note that the call to the
doSetmethod ofLockingTransactionis passedthis(a reference to the Ref). The change that will be applied within the transaction is established by thedoSetmethod but that change is effected within therunmethod ofLockingTransaction. When the transaction is run successfullynotifyWatchesis called using the reference to the Ref recorded bydoSet.