 
   IWatchable
   (-notify-watches [this oldval newval]
-    (reduce-kv (fn [_ key f]
-                 (f key this oldval newval)
-                 nil)
-               nil watches))
+    (ra-notify-watches this oldval newval))
 
   (-add-watch [this k wf]
     (set! watches (assoc watches k wf)))

  IHash
  (-hash [this] (goog/getUid this)))

(defn make-reaction [f & {:keys [auto-run on-set on-dispose derefed]}]
  (let [runner (if (= auto-run true) run auto-run)
        active (not (nil? derefed))

  (run [this]))

(defprotocol IComputedImpl
  (-peek-at [this]))

(def clean 0)
(def maybe-dirty 1)
(def is-dirty 2)

(declare reaction?)

(defn- ra-notify-watches [ra oldval newval]
  (reduce-kv (fn [_ key f]
               (f key ra oldval newval)
               nil)
             nil ra.watches))

(defn- ra-check-clean [ra]
  (when (== ra.dirty? maybe-dirty)
    (set! ra.norun? true)
    (doseq [w ra.watching]
      (when (reaction? w)
        (-deref w)))
    (set! ra.norun? false)
    (when (== ra.dirty? maybe-dirty)
      (set! ra.dirty? clean))))

(defn- ra-handle-change [ra sender oldval newval]
  (when ra.active?
    (let [old-dirty ra.dirty?]
      (set! ra.dirty? (max ra.dirty?
                           (if (identical? oldval newval)
                             (if (reaction? sender)
                               maybe-dirty clean)
                             is-dirty)))
      (if (and ra.auto-run (not ra.norun?))
        (do
          ;; FIXME: is this correct?
          (when (== ra.dirty? maybe-dirty)
            (binding [*ratom-context* (js-obj)]
              (ra-check-clean ra)))
          (when-not (== ra.dirty? clean)
            ((or ra.auto-run run) ra)))
        (when (== old-dirty clean)
          (ra-notify-watches ra ra.state ra.state))))))

(defn- ra-update-watching [ra derefed]
  (doseq [w derefed]
    (when-not (contains? ra.watching w)
      (add-watch w ra ra-handle-change)))
  (doseq [w ra.watching]
    (when-not (contains? derefed w)
      (remove-watch w ra)))
  (set! ra.watching derefed))

(deftype Reaction [f ^:mutable state ^:mutable dirty? ^:mutable active?
                   ^:mutable watching ^:mutable watches
