Skip to content
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

fixes #40: throw when map is mutated in getOrInsertComputed callbacks #73

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

michaelficarra
Copy link
Member

@michaelficarra michaelficarra commented Nov 18, 2024

Fixes #40. Alternative to #71 (closes #71).

Other currently unexplored options:

  1. Throw only if the value is different.
  2. Lock the map before calling the callback and throw in any mutating operation called from within the callback.
    1. The difference here being that we could catch and prohibit any mutation rather than just the addition of the key we're currently setting.

Copy link

@bakkot bakkot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. TypeError seems not quite right, but we don't have a better one and it's not worth introducing a new error kind just for this I expect.

@jridgewell
Copy link
Member

Why not just insert a { [[Key]]: _key_, [[Value]]: *undefined* } before invoking the callback, then mutate that record with its new value afterwards?

@bakkot
Copy link

bakkot commented Nov 18, 2024

The callback could remove and re-add the key, so that wouldn't be sufficient on its own. With how the spec machinery is written I guess you could check to see if the entry record still has the right [[Key]], but that doesn't actually match how implementations work under the hood.

I expect doing the additional map update would be more expensive for the common case of no mutation in the callback, so that doesn't seem worth it.

@zloirock
Copy link
Contributor

It will make polyfilling of those methods too painful that could slowdown Map and WeakMap at all for a significant part of users for years.

@bakkot
Copy link

bakkot commented Nov 19, 2024

@zloirock The polyfill is literally just

Map.prototype.getOrInsertComputed = function (key, callback) {
  if (typeof callback !== 'function') throw new TypeError;
  if (this.has(key)) return this.get(key);
  let value = callback(key);
  if (this.has(key)) throw new TypeError;
  this.set(key, value);
  return value;
};

(except with intrinsic versions of get/set/has/TypeError, obviously)

There is no reason this should slow down anything else, nor be particularly slow itself. Maybe you are thinking of a different behavior than the one this is actually proposing? This isn't the "lock the map" thing, it's just checking to see if the key was inserted in the map again after calling the callback.

@zloirock
Copy link
Contributor

zloirock commented Nov 19, 2024

This isn't the "lock the map" thing, it's just checking to see if the key was inserted in the map again after calling the callback.

Ah, in this case, it's fine - after the mentioned issue, I was sure that this option implies map locking that will be added in the future. Sorry -)

@dead-claudia
Copy link

Will note that my optimization note suggestion in #40 (comment) also applies here with little modification.

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

Successfully merging this pull request may close these issues.

Suggestion: lock the map during access to prevent recursive modification
5 participants