Hi Andy,
Having thunk on it, I will try to articulate my preference for nil over {} more clearly: (clojure.data/diff {:x {:y 1}} {:x {}}) ;; => ({:x {:y 1}} {:x nil} nil) Do you agree the current result is wrong? :x nil is not 'in' {:x {}} nil is not associative so in this context does not mean empty, it means literally nil. only (clojure.data/diff {:x {:y 1}} {:x nil}) should return {:x nil} as the 'only in b' result. So choosing between ({:x {:y 1}} nil nil) vs ({:x {:y 1}} {:x {}} nil) as solutions: I argue that using {} adds an unnecessary special case. Non-empty absence uses nil to indicate nothing was added. (clojure.data/diff {:x {:y 1, :z 2}} {:x {:z 2}}) ;; => ({:x {:y 1}} nil {:x {:z 2}}) It is not correct to say that :x {} was added as a replacement value, because (clojure.data/diff {:x {:z 2}} {:x {:y 1, :z 2}}) ;; => (nil {:x {:y 1}} {:x {:z 2}}) {:y 1} is not a replacement, but is associative (there is {:y 1, :z 2} in both). It is correct to say that :x {} equally represents no change, but additionally flags the collection is now empty. For my part I do not think clojure.data/diff should do this. It might be useful information, but is easily identifiable state, and comes at the cost of introducing a special case. Also consider this case: (clojure.data/diff {} {:x {}}) ;; => (nil {:x {}} nil) There was no map associated with :x in the first argument, but there is in the second argument. Here it accurately represents differential participation and so should be distinguishable from (clojure.data/diff {:x {:y 1}} {:x {}}). What do you think? Regarding your questions about patchin specifically: On Sat, Feb 21, 2015 at 4:36 PM, Andy Fingerhut <andy.finger...@gmail.com> wrote: > Do you plan to support sending a different 'diff' in each of these cases, > such that the 'receiver' can end up in the same final state, for each of > these case? Yes, patchin works this way. > Or perhaps the idea is that some of those are not supported? I claim that every data representation/change that conforms to EDN is currently supported :) Thank you for the thoughtful test cases, I recognized an opportunity to remove some redundancy in patch creation while experimenting with them. > both sides is {:x {:y 1}}, and the 'sender' wants to change to one of these > states: Here is some REPL output of the patches generated which successfully cause those transformations: (a) patchin> (diff {:x {:y 1}} {:x nil}) ;; => [{:x nil}] (b) patchin> (diff {:x {:y 1}} {:x {}}) ;; => [{:x {}}] (bb) patchin> (diff {:x {:y 1}} {:x []}) ;; => [{:x []}] (c) patchin> (diff {:x {:y 1}} {:x {:y nil}}) ;; => [{:x {:y nil}}] All of these are 'replace the entire state with this', because the equivalent dissoc/assoc steps create a larger patch than the final state. To demonstrate transformations, we need to add some extra data: (a) patchin> (diff {:x {:y "22"}, :z "somelargedata"} {:x nil :z "somelargedata"}) ;; => [{} {:x nil}] {} indicates nothing to dissoc/disj {:x nil} are the things to replace. so the second transform results in {:x nil :z "somelargedata"} patchin> (patch {:x {:y "22"}, :z "somelargedata"} [{} {:x nil}]) ;; => {:z "somelargedata", :x nil} (b) patchin> (diff {:x {:y "22"}, :z "somelargedata"} {:x {} :z "somelargedata"}) ;; => [{:x {:y 1}} {}] {:x {:y 1}} are the things to remove (1 is an arbitrary non-map/set terminal). This indicates the paths to dissoc/disj; in this case there is only one path [:x :y] so the first transform results in: {:x {} :z "somelargedata"} {} means nothing to add patchin> (patch {:x {:y "22"}, :z "somelargedata"} [{:x {:y 1}} {}]) ;; => {:z "somelargedata", :x {}} (bb) patchin> (diff {:x {:y "22"}, :z "somelargedata"} {:x [] :z "somelargedata"}) ;; => [{} {:x []}] Same as (a), :x is replaced with [] patchin> (patch {:x {:y "22"}, :z "somelargedata"} [{} {:x []}]) ;; => {:z "somelargedata", :x []} (c) patchin> (diff {:x {:y "22"}, :z "somelargedata"} {:x {:y nil} :z "somelargedata"}) ;; => [{} {:x {:y nil}}] Replacing path [:x :y] with nil patchin> (patch {:x {:y "22"}, :z "somelargedata"} [{} {:x {:y nil}}]) ;; => {:z "somelargedata", :x {:y nil}} The way that patchin identifies the difference between empty collections and nil is by monkey patching data/diff-associative-key to avoid the empty associative issue. Thank you for your interest. Regards, Timothy -- 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/d/optout.