      (-remove-watch ref key)
      (sully))))
 
+(defn get-add-watch* [ref]
+  (cond
+    (satisfies? IInvalidates ref)
+    add-invalidation-watch
+    (satisfies? IWatchable ref)
+    add-watch))
+
+(defn get-remove-watch* [ref]
+  (cond
+    (satisfies? IInvalidates ref)
+    remove-invalidation-watch
+    (satisfies? IWatchable ref)
+    remove-watch))
+
+(defn get-add-remove-watch* [ref]
+  (cond
+    (satisfies? IInvalidates ref)
+    [add-invalidation-watch remove-invalidation-watch]
+    (satisfies? IWatchable ref)
+    [add-watch remove-watch]))
+
 (deftype ReactiveComputation [^:mutable state ^:mutable dirty f ^:mutable deps meta
                               ^:mutable watches ^:mutable invalidation-watches sully]
   Object

      state
      (binding [*register-dep*
                (fn [ref]
                  (cond
                    (satisfies? IInvalidates ref)
                    (-add-invalidation-watch ref this sully)
                    (satisfies? IWatchable ref)
                    (-add-watch ref this sully)))]
        (set! dirty false)
        (let [old-val state
              new-val (f)]

    (set! (.-sully reactive) (make-sully-fn reactive))
    reactive))

(declare update-lens-state)

(defn- add-lens-watch [lens ref]
  ((get-add-watch* ref)
   ref lens
   (fn sully-lens
     ([]
      (set! (.-dirty lens) true)
      (when-not (empty? (.-watches lens))
        (update-lens-state lens ref)))
     ([_ _]
      (remove-invalidation-watch ref lens))
     ([_ _ old-value new-value]
      (remove-watch ref lens)
      (sully-lens)))))

(defn- update-lens-state [lens ref]
  (set! (.-dirty lens) false)
  (add-lens-watch lens ref)
  (let [new-value ((.-getter lens) @ref)
        old-value (.-state lens)]
    (when (not= old-value new-value)
      (set! (.-state lens) new-value)
      (when-not (empty? (.-watches lens))
        (-notify-watches lens old-value new-value)))
    new-value))

(defn- lens-swap! [ref getter setter f]
