tc39 / proposal-upsert

ECMAScript Proposal, specs, and reference implementation for Map.prototype.upsert
https://tc39.es/proposal-upsert/
MIT License
204 stars 14 forks source link

Simpler alternative: `map.update(key, updater)` #37

Closed dead-claudia closed 3 years ago

dead-claudia commented 3 years ago

H/T to @bergus for the idea.

The idea is using an optional value. Also, I'd drop the map and key parameters in the callback - they're redundant and I don't see them garnering much use anyways.

// Rough approximation
Map.prototype.update = function (key, func) {
    const current = {
        exists: this.has(key),
        value: this.get(key),
    }
    const replacement = func(current)
    if (!replacement.exists) this.delete(key)
    else this.set(key, replacement.value)
}

Here's some examples of how it might be used:

// Increment a counter or initialize it to 0 if empty
counts.update(key, (existing, none) => existing === none ? 0 : existing + 1)

// Normalization of values during insertion
map.update(key, (existing, none) => existing === none ? value : existing).doThing();

// Either update or insert for a specific key
map.update(key, (existing, none) => existing === none ? value : updated)

// Just insert if missing
map.update(key, (existing, none) => existing === none ? value : existing)

// Just update if present
map.update(key, (existing, none) => existing === none ? none : updated)

For the no-op case, it's as simple as this: map.update(key, (existing, none) => existing). And map.set(key, value) is equivalent to map.update(key, () => value)

dead-claudia commented 3 years ago

Closing as this...isn't the best of ideas, and in essence requires an unelidable allocation every update (making it even more of a bad candidate for a replacement). Also, it's not particularly idiomatic for the JS standard library.