Skip to content

updateIn doesn't properly handle notSetValue #1657

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
migueloller opened this issue Nov 30, 2018 · 8 comments
Closed

updateIn doesn't properly handle notSetValue #1657

migueloller opened this issue Nov 30, 2018 · 8 comments

Comments

@migueloller
Copy link

What happened

updateIn doesn't properly handle notSetValue.

How to reproduce

const { updateIn } = require('immutable')
const original = { x: { y: { z: 123 } } }
const NOT_SET = { NOT_SET: true }
console.log(updateIn(original, ['x', 'y'], NOT_SET, val => NOT_SET)) // { x: { y: { NOT_SET: true } } }

Expected the log output to be { x: {} } instead. Is this intended behavior?

@lukaswelinder
Copy link

Your example is a bit confusing, could you clarify?

From what I can see, the value at ['x', 'y'] is defined, so by returning NOT_SET from your update function, you are effectively updating that value because the notSetValue is ignored and the return is compared against the existing value.

This code provides the output you are expecting:

const { updateIn } = require('immutable')
const original = { x: { } }
const NOT_SET = { NOT_SET: true }
console.log(updateIn(original, ['x', 'y'], NOT_SET, val => NOT_SET)) // { x: {} } }

I'm fairly certain that this is the intended behavior.

@migueloller
Copy link
Author

From what I understood reading the docs. The third argument (notSetValue) is used to determine what should be returned from the callback to represent a "deletion". In this case, I'm using an object, { NOT_SET: true } to represent this value, instead of the default undefined. If the returned value from the callback is this value, the field at the key path, ['x', 'y'], in this case, should be unset. Is that not the expected behavior?

@Methuselah96
Copy link
Contributor

No, the third argument, is what is passed into the updater function if there is no value at that key path, so this is indeed correct behavior.

@migueloller
Copy link
Author

migueloller commented Nov 21, 2020

Interesting, so if I don't want to use undefined to mean "not set", then I would do something like this?

const { updateIn } = require('immutable')
const original = { x: { y: undefined } }
const NOT_SET = { NOT_SET: true }
// { x: { y: undefined } }
console.log(updateIn(original, ['x', 'y'], NOT_SET, val => {
  if (val === NOT_SET) return 'foo'

  return val
}))

And if I wanted to actually remove y, I would use removeIn?

@Methuselah96
Copy link
Contributor

Yes, exactly. I agree that it's not the most intuitive behavior just by looking at the parameter name.

@migueloller
Copy link
Author

The one confusing thing is how notSetValue is returned if one called updateIn with a value that is NOT_SET from Immutable.js' perspective. Wouldn't it make more sense to have notSetValue only be used within the callback and not be returned by updateIn. I'm referencing this line:

return updatedValue === NOT_SET ? notSetValue : updatedValue;

@Methuselah96
Copy link
Contributor

Methuselah96 commented Nov 21, 2020

@migueloller That is interesting. I had to dig into it more, and it appears that that behavior is there solely for the sake of removeIn. Otherwise it would just return updatedValue.

@migueloller
Copy link
Author

Gotcha. And I guess because notSetValue is just undefined by default then removeIn will return undefined in that case. As for updateIn, what would be the right call here? To continue to return notSetValue, to always return undefined?

The reason I expected updateIn to "remove" values if I returned notSetValue from updater was because of that notSetValue being returned by updateIn. I'll admit that most people don't look at the source. The reason I was was because I was implementing the Immutable.js APIs to create operations to use with an operational transforms algorithm. And the assumption I made then, apparently incorrectly, was that notSetValue would allow the called to pass a custom reference to replace undefined with the meaning of "not set". Meaning that if it was returned from updater, then it would remove the relevant key, and if it was the "root" object then it would just return it, as we see in that line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants