zcaudate
zcaudate

Reputation: 14258

how do refs notify its watches in clojure?

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?

Upvotes: 3

Views: 386

Answers (2)

Alex Stoddard
Alex Stoddard

Reputation: 8344

The call to notifyWatches you are looking for occurs in the run method of the LockingTransaction class.

Changes to refs happen in transactions. Note that the call to the doSet method of LockingTransaction is passed this (a reference to the Ref). The change that will be applied within the transaction is established by the doSet method but that change is effected within the run method of LockingTransaction. When the transaction is run successfully notifyWatches is called using the reference to the Ref recorded by doSet.

Upvotes: 3

Arthur Ulfeldt
Arthur Ulfeldt

Reputation: 91577

clojure.lang.Ref extends clojure.lang.ARef which has the watches and provides the notifyWatches method

Upvotes: 2

Related Questions