@@ -15,6 +15,17 @@ REMOTE_ORIGIN <- NULL
1515 if (inherits(value , " Prelim" )) value else yr :: Prelim $ any(value )
1616}
1717
18+ # Compare a CRDT-stored value against a candidate R value for change detection.
19+ # The CRDT normalizes types on round-trip (notably integers come back as doubles),
20+ # so identical() alone reports spurious changes;
21+ # fall back to a tolerant value-wise comparison when types differ.
22+ .values_equal <- function (stored , value ) {
23+ if (identical(stored , value )) {
24+ return (TRUE )
25+ }
26+ length(stored ) == length(value ) && isTRUE(all.equal(stored , value ))
27+ }
28+
1829# ' Holds the currently-active `yr::Transaction`, or NULL. Shared by a
1930# ' WidgetBase and its storages so storage operations can join an ongoing
2031# ' transaction instead of opening a nested one.
@@ -214,7 +225,9 @@ YAttrStorage <- R6::R6Class(
214225 update = function (value ) {
215226 private $ with_transaction(
216227 function (trans ) {
217- if (identical(private $ attrs $ get(trans , private $ key ), value )) {
228+ # The CRDT may normalizes types on round-trip (e.g. an integer -> double)
229+ # so a strict identical() would treat an unchanged value as changed.
230+ if (.values_equal(private $ attrs $ get(trans , private $ key ), value )) {
218231 return (FALSE )
219232 }
220233 private $ attrs $ insert(trans , private $ key , .as_prelim(value ))
0 commit comments