GithubHelp home page GithubHelp logo

Comments (7)

rtfeldman avatar rtfeldman commented on July 20, 2024

There's currently logic to do this in some situations: merge determines whether changes were made and then returns the unmodified original object if not.

The question here is how far it ought to go in deciding whether any changes were made. It currently considers the example you gave a change because it does referential equality checking to determine that. If instead it did deep (value-based) equality checking, it would realize that this was not actually a change and you'd get the result you were hoping for. 😃

This isn't yet possible because the deepEquals branch hasn't landed, but assuming it had, there's still a tradeoff to consider. Doing this check on every merge can get expensive, especially when merging large data structures. It would probably still unlock a considerable performance boost in the case of shouldComponentUpdate, but could be a substantial performance hit in other use cases.

My general feeling is that once deepEquals is in (which has been on the backburner for me, but which mainly just needs tests at this point), merge should use it by default for this purpose, but should accept an optional alternative "change-detector" function so you can save yourself from a huge performance hit on large data structures.

from seamless-immutable.

crudh avatar crudh commented on July 20, 2024

@rtfeldman cases like this could be handled by a custom merger if we add the following to addToResult in the merge function:

Right now it looks like:

var mergerResult = merger && merger(currentObj[key], immutableValue, config);

If we extend that to:

var mergerResult = merger && merger(currentObj[key], immutableValue, config);
if (mergerResult && mergerResult === currentObj[key]) return;

Then if a merger returns something and it is the same thing as the property in the currentObj we could abort addToResult.

Combining that with a custom merger that returns the array from the currentObj if they contain the same items:

function equalityArrayMerger(current, other) {
  if (!(current instanceof Array) || !(other instanceof Array)) return;
  if (current.length !== other.length) return;

  for (var i = 0; i < current.length; i++) {
    if (current[i] !== other[i]) return;
  }

  return current;
}

would give the desired results.

But not sure if it is worth adding if there is another long term goal with deepEquals? It's a minor change but it will add another check in the addToResult function. And this was only a quick test, I haven't checked how/if it affects other things.

from seamless-immutable.

rtfeldman avatar rtfeldman commented on July 20, 2024

Yeah, that seems like a good implementation. I'd change the second line to this, though:

if (merger && mergerResult === currentObj[key]) return;

That way the conditional can still pass if the value happens to be falsy in both places.

As far as merge goals, the goals with deepEquals would be (1) to change the default implementation to use deepEquals for change detection over ===, and (2) to allow users to specify a custom function to do this if necessary.

from seamless-immutable.

crudh avatar crudh commented on July 20, 2024

@cr0cK: now that PR #41 has been merged you should be able, after the next release, to pass in the following or similar to the merge to get your example to work:

function equalityArrayMerger(current, other) {
  if (!(current instanceof Array) || !(other instanceof Array)) return;
  if (current.length !== other.length) return;

  for (var i = 0; i < current.length; i++) {
    if (current[i] !== other[i]) return;
  }

  return current;
}

...
> i2 = i.merge(o2, {merger: equalityArrayMerger})
{ a: [ 1, 2 ] }
> i === i2
true

It will override the merge for array properties and return the same reference if they contain the same list of values in both objects.

Note that it will not work with current master until a grunt build has been run.

from seamless-immutable.

cr0cK avatar cr0cK commented on July 20, 2024

Thank you @crudh, It looks nice :)

What do you think about to make this behavior as the default one?

from seamless-immutable.

crudh avatar crudh commented on July 20, 2024

@cr0cK: it's released now. And if you use Node/Browserify I have added the equalityArrayMerger in this project if you prefer that instead of copying the function above.

As for the default behaviour I agree with what @rtfeldman said above, as long as it is easy to get back to the current behaviour when a deep check isn't needed or is too expensive.

from seamless-immutable.

jedwards1211 avatar jedwards1211 commented on July 20, 2024

Why do some kind of deepEquals test when you could just use recursive merging to determine if anything has changed? Here's a rough 17-line deep merge implementation (not thoroughly tested, and one would want to make it customizable):

function mergeDeep(a, b) {
  if (a instanceof Object || a instanceof Array) {
    if (!b) return a;
    var remade;
    for (var key in b) {
      if (b.hasOwnProperty(key)) {
        var merged = mergeDeep(a[key], b[key]);
        if (merged !== a[key]) {
          if (!remade) remade = a.asMutable();
          remade[key] = merged;
        }
      }
    }
    return remade ? Immutable(remade) : a;
  }
  return b;
}

Here was my testcase that works with this mergeDeep but not merge(..., {deep: true}):

var a = Immutable({
  plots: [
    {
      traces: [
        {channel: 'a'},
        {channel: 'b'}
      ]
    }
  ]
});
var b = mergeDeep(a, {
  plots: [
    {
      traces: [
        {channel: 'a'},
        {channel: 'b', min: 0, max: 100}
      ]
    }
  ]
});

console.log(a.plots[0].traces[0] === b.plots[0].traces[0]); // should be true
console.log(a.plots[0].traces[1] === b.plots[0].traces[1]); // should be false

Note that since this function treats arrays like number-keyed maps, mergeDeep(Immutable([1,2,,,5]), [,3,4]) would produce [1,3,4,,5] with this implementation, which is exactly analogous to map merging (and I believe the way Immutable.js mergeDeep works). Another common merge type would be for the output to be deep equal to b, but with all original values from a that were equal:

function updateDeep(a, b) {
  if (a instanceof Object || a instanceof Array) {
    if (!b) return a;
    var remade;
    for (var key in b) {
      if (b.hasOwnProperty(key)) {
        var updated = updateDeep(a[key], b[key]);
        if (updated !== a[key]) {
          if (!remade) remade = a.asMutable();
          remade[key] = updated;
        }
      }
    }
    for (var key in a) {
      if (!b.hasOwnProperty(key)) {
        if (!remade) remade = a.asMutable();
        delete remade[key];
      }
    }
    return remade ? Immutable(remade) : a;
  }
  return b;
}

from seamless-immutable.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.