I don't really have anything to add to this thread but I will say that Om's
use of identical? is an implementation detail that's likely to change. =
already does an identical? check, ideally Om could use not= in the future
instead of (not (identical? ...)).

David


On Tue, Feb 25, 2014 at 12:54 PM, Brian Craft <craft.br...@gmail.com> wrote:

> No, my question isn't "is there a way" to do this. I'm sure there are a
> dozen ways to do it. My question is about a specific way of doing it. In
> particular, if your solution does not involve calling (identical? ..), then
> it's not what I'm asking about.
>
> In om core there's a call to identical? under the :shouldComponentUpdate
> key, which I suspect is what David was talking about in his blog posts
> about avoiding deep compares via immutable data structures. My question is
> about whether that has implications for how you write algorithms that
> update state, and whether the semantics of update-in (or assoc, really)
> that allow it to return the same object if the update would return an
> identical object, are related to this mechanism, if these semantics are
> documented, and if they depend on the data type being assoc'd.
>
>
>
> On Monday, February 24, 2014 6:27:02 PM UTC-8, t x wrote:
>
>> Perhaps I mis-interpreted your question.
>>
>> I thought the question asked was:
>>
>>
>> GIven:
>>   * pure function "func"
>>   * some object "obj"
>>   * (def a (func obj))
>>   * (def b (func obj))
>>
>> Example:
>>   * obj = [1 2 3]
>>   * (defn func [lst] (map #(* 2 %) lst))
>>
>> Then:
>>   * is there a O(1) way to check if (= a b) ?
>>
>>   In the above, we create two _different_ lists, both of which stores
>> [2 4 6], thus they're equal, but not identical
>>
>> Proposed solution:
>>   tag the returned-value with a meta object, where the meta object
>> describes how the object was computed.
>>
>>   in this case, both [2 4 6] would have _identical_ meta objects,
>> since they're both from the list [1 2 3]
>>
>>
>>
>>
>>
>> On Mon, Feb 24, 2014 at 5:56 PM, Brian Craft <craft...@gmail.com> wrote:
>> > You're solving a similar problem, but I'm asking specifically about
>> using
>> > object identity, not equality, for tracking changes in a nested
>> structure.
>> >
>> >
>> > On Monday, February 24, 2014 1:42:03 PM UTC-8, t x wrote:
>> >>
>> >> I finally have a chance to give back. :-)
>> >>
>> >> I hacked up a newb's half-React. It does tree diffing + dom updating,
>> >> but not the virtual event handling system.
>> >>
>> >> I ran into this exact problem, and solved it as follows:
>> >>
>> >>
>> >> ## problem definition:
>> >>
>> >> render: data -> dom
>> >> tree-diff: dom * dom -> list of dom-update-actions
>> >>
>> >> we want to avoid "deep tree diffing" on tree-diff
>> >>
>> >> the key idea is as follows:
>> >>
>> >>   when render is called twice with same args,
>> >>
>> >>   * we still have to recompute every time
>> >>   * we don't have to re-compare every time
>> >>
>> >> if render is a pure function, we do somethign like:
>> >>
>> >> (defn render [data]
>> >>   (with-meta (render-pure data) {:pure data}))
>> >>
>> >> (render-pure data) gives us a dom-tree
>> >> we tag it with a meta project, telling us that it came from "data",
>> >> and that it was a pure function
>> >>
>> >>
>> >> then, doing the tree-diff stage, we do:
>> >>
>> >>
>> >> (defn tree-diff [old-dom new-dom]
>> >>   (let [mo (meta old-dom)
>> >>         no (meta new-dom)]
>> >>     (if (and (:pure mo) (:pure no) (= (:pure mo) (:pure no)))
>> >>       .. ah, they're from the same pure function, thus the same ...
>> >>       ... okay, let's do expensive deep diff)))
>> >>
>> >>
>> >> so basically, we abuse meta objects, record
>> >>
>> >>   * what data gave us this dom tree ?
>> >>   * was the func that gave us the dom tree pure ?
>> >>
>> >> And if so, we just do a equality check on the data -- which are are
>> >> _not_ "regenerating" and thus matches an equality check.
>> >>
>> >>
>> >> Please let me if:
>> >>
>> >>   (a) this resolves the issue
>> >>   (b) I completely misunderstood the question
>> >>
>> >>
>> >> Thanks!
>> >>
>> >>
>> >>
>> >>
>> >>
>> >>
>> >> On Mon, Feb 24, 2014 at 1:00 PM, Brian Craft <craft...@gmail.com>
>> wrote:
>> >> > This is vaguely related to David's posts about om/react, where he
>> talks
>> >> > about optimizing state change tracking by checking object identity
>> on
>> >> > immutable objects: deep compares can be avoided if same identity
>> implies
>> >> > no
>> >> > changes.
>> >> >
>> >> > My first thought was that there are many algorithms that will give
>> you a
>> >> > new
>> >> > object every time, even if nothing has changed.  E.g. if your state
>> has
>> >> > an
>> >> > array whose elements must be validated, doing a map over the
>> elements
>> >> > will
>> >> > give you a new array every time, even if it makes no changes.
>> >> >
>> >> > Enforcing non-negative values, for instance:
>> >> >
>> >> > => (let [x {:a [1 -2 3]}] (update-in x [:a] (fn [y] (mapv #(if (< %
>> 0) 0
>> >> > %)
>> >> > y))))
>> >> > {:a [1 0 3]}
>> >> >
>> >> > In the following case the values are already non-negative, but we
>> still
>> >> > get
>> >> > a new object:
>> >> >
>> >> > => (let [x {:a [1 2 3]}] (identical? x (update-in x [:a] (fn [y]
>> (mapv
>> >> > #(if
>> >> > (< % 0) 0 %) y)))))
>> >> > false
>> >> >
>> >> > One can imagine trying to rewrite this so it passes through the
>> vector
>> >> > if
>> >> > nothing has changed. E.g.
>> >> >
>> >> > => (let [x {:a [1 2 3]}] (identical? x (update-in x [:a] (fn [y]
>> (reduce
>> >> > (fn
>> >> > [v i] (if (< (v i) 0) (assoc v i 0) v)) y (range (count y)))))))
>> >> > true
>> >> >
>> >> > => (let [x {:a [1 -1 3]}] (identical? x (update-in x [:a] (fn [y]
>> >> > (reduce
>> >> > (fn [v i] (if (< (v i) 0) (assoc v i 0) v)) y (range (count y)))))))
>> >> > false
>> >> >
>> >> > I expect many algorithms would need to be reworked like this in
>> order to
>> >> > rely on object identity for change tracking. Is this madness? Am I
>> >> > thinking
>> >> > about this the wrong way?
>> >> >
>> >> >
>> >> > An interesting note here is that the next-to-last update-in, above,
>> >> > returned
>> >> > the same object. I didn't know update-in could return the same
>> object. A
>> >> > simpler example:
>> >> >
>> >> > => (let [x {"a" [1 2 3]} y (update-in x ["a"] (fn [z] z))] [x y
>> >> > (identical?
>> >> > x y)])
>> >> > [{"a" [1 2 3]} {"a" [1 2 3]} true]
>> >> >
>> >> > => (let [x {"a" [1 2 3]} y (update-in x ["a"] (fn [z] [1 2 3]))] [x
>> y
>> >> > (identical? x y)])
>> >> > [{"a" [1 2 3]} {"a" [1 2 3]} false]
>> >> >
>> >> >
>> >> > Is this some kind of optimization in update-in, that it doesn't
>> create a
>> >> > new
>> >> > object if the new attribute is identical to the old attribute? Is it
>> >> > peculiar to the data type? Is it documented anywhere?
>> >> >
>> >> >
>> >> > --
>> >> > You received this message because you are subscribed to the Google
>> >> > Groups "Clojure" group.
>> >> > To post to this group, send email to clo...@googlegroups.com
>> >> > Note that posts from new members are moderated - please be patient
>> with
>> >> > your
>> >> > first post.
>> >> > To unsubscribe from this group, send email to
>> >> > clojure+u...@googlegroups.com
>> >> > For more options, visit this group at
>> >> > http://groups.google.com/group/clojure?hl=en
>> >> > ---
>> >> > You received this message because you are subscribed to the Google
>> >> > Groups
>> >> > "Clojure" group.
>> >> > To unsubscribe from this group and stop receiving emails from it,
>> send
>> >> > an
>> >> > email to clojure+u...@googlegroups.com.
>> >> > For more options, visit https://groups.google.com/groups/opt_out.
>> >
>> > --
>> > You received this message because you are subscribed to the Google
>> > Groups "Clojure" group.
>> > To post to this group, send email to clo...@googlegroups.com
>> > Note that posts from new members are moderated - please be patient with
>> your
>> > first post.
>> > To unsubscribe from this group, send email to
>> > clojure+u...@googlegroups.com
>> > For more options, visit this group at
>> > http://groups.google.com/group/clojure?hl=en
>> > ---
>> > You received this message because you are subscribed to the Google
>> Groups
>> > "Clojure" group.
>> > To unsubscribe from this group and stop receiving emails from it, send
>> an
>> > email to clojure+u...@googlegroups.com.
>> > For more options, visit https://groups.google.com/groups/opt_out.
>>
>  --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with
> your first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to