No. The raised concern has been common among developers and the main issue is that `set` returns itself which is the least useful pattern.
Your suggestion would make sense if `const value = map.has(key) ? map.get(key) : map.set(key, createValue())` instead ES went for chain ability and yet, to date, I have to see a single usage of `map.set(a, 1).set(b, 2)` in the wild. On top of that, needing to `.has` and then `.get` is a performance shenanigan many would likely avoid at all costs 'cause AFAIK in no engine `.has(key)` temporarily retains last searched key to boost up the immediate `.get(key)` later on so having a `.putIfAbsent(key, createValue())` that returns either the found or the created value is a clear win. On Thu, Oct 11, 2018 at 6:20 AM Jordan Harband <[email protected]> wrote: > Thanks, your correction explains what the benefit would be (the awkward > need to cache the value). However this seems simpler to me: `if > (!map.has(key)) { map.set(key, getValue()); } const value = map.get(key);` > > On Wed, Oct 10, 2018 at 9:07 PM Isiah Meadows <[email protected]> > wrote: > >> I presume you mean this? >> >> ```js >> // Proposed >> map.putIfAbsent(key, init) >> >> // How you do it now >> let value >> if (map.has(key)) { >> value = map.get(key) >> } else { >> map.set(key, value = init()) >> } >> ``` >> >> BTW, I'd like to see this make it myself, just slightly different: >> >> - How you call it: `map.getOrPut(key, init, thisValue=undefined)` >> - How `init` is called: `init.call(thisValue, key, map)` >> >> This pattern is incredibly common for caching. It'd be nice if I didn't >> have to repeat myself so much with it. I would be more willing to stuff it >> in a utility function if it weren't for the fact the use cases often entail >> performance-sensitive paths, and engines aren't reliable enough in my >> experience with inlining closures passed to non-builtins. >> >> On Wed, Oct 10, 2018 at 22:54 Jordan Harband <[email protected]> wrote: >> >>> It seems like your proposed `const value = map.putIfAbsent(key, >>> getExpensiveValue);` is achievable already with `const value = map.has(key) >>> ? map.get(key) : map.set(getExpensiveValue());` - am I understanding your >>> suggestion correctly? >>> >>> On Wed, Oct 10, 2018 at 12:46 AM Man Hoang <[email protected]> >>> wrote: >>> >>>> Consider the following function >>>> >>>> ``` js >>>> >>>> /** >>>> >>>> * Parses the locale sensitive string [value] into a number. >>>> >>>> */ >>>> >>>> export function parseNumber( >>>> >>>> value: string, >>>> >>>> locale: string = navigator.language >>>> >>>> ): number { >>>> >>>> let decimalSeparator = decimalSeparators.get(locale); >>>> >>>> if (!decimalSeparator) { >>>> >>>> decimalSeparator = Intl.NumberFormat(locale).format(1.1)[1]; >>>> >>>> decimalSeparators.set(locale, decimalSeparator); >>>> >>>> } >>>> >>>> >>>> >>>> let cleanRegExp = regExps.get(decimalSeparator); >>>> >>>> if (!cleanRegExp) { >>>> >>>> cleanRegExp = new RegExp(`[^-+0-9${decimalSeparator}]`, 'g'); >>>> >>>> regExps.set(decimalSeparator, cleanRegExp); >>>> >>>> } >>>> >>>> >>>> >>>> value = value >>>> >>>> .replace(cleanRegExp, '') >>>> >>>> .replace(decimalSeparator, '.'); >>>> >>>> >>>> >>>> return parseFloat(value); >>>> >>>> } >>>> >>>> >>>> >>>> const decimalSeparators = new Map<string, string>(); >>>> >>>> const regExps = new Map<string, RegExp>(); >>>> >>>> ``` >>>> >>>> >>>> >>>> This function can be simplified quite a bit as follows >>>> >>>> ``` js >>>> >>>> export function parseNumber( >>>> >>>> value: string, >>>> >>>> locale: string = navigator.language >>>> >>>> ): number { >>>> >>>> const decimalSeparator = decimalSeparators.putIfAbsent( >>>> >>>> locale, () => Intl.NumberFormat(locale).format(1.1)[1]); >>>> >>>> >>>> >>>> const cleanRegExp = regExps.putIfAbsent( >>>> >>>> decimalSeparator, () => new >>>> RegExp(`[^-+0-9${decimalSeparator}]`, 'g')); >>>> >>>> >>>> >>>> value = value >>>> >>>> .replace(cleanRegExp, '') >>>> >>>> .replace(decimalSeparator, '.'); >>>> >>>> >>>> >>>> return parseFloat(value); >>>> >>>> } >>>> >>>> ``` >>>> >>>> if `Map` has the following instance method >>>> >>>> ``` js >>>> >>>> export class Map<K, V> { >>>> >>>> /** >>>> >>>> * Look up the value of [key], or add a new value if it isn't there. >>>> >>>> * >>>> >>>> * Returns the value associated to [key], if there is one. >>>> >>>> * Otherwise calls [ifAbsent] to get a new value, associates [key] >>>> to >>>> >>>> * that value, and then returns the new value. >>>> >>>> */ >>>> >>>> putIfAbsent(key: K, ifAbsent: () => V): V { >>>> >>>> let v = this.get(key); >>>> >>>> if (v === undefined) { >>>> >>>> v = ifAbsent(); >>>> >>>> this.set(key, v); >>>> >>>> } >>>> >>>> return v; >>>> >>>> } >>>> >>>> } >>>> >>>> ``` >>>> >>>> >>>> >>>> Java's Map has a `putIfAbsent` method, which accepts a value rather >>>> than a function for the second parameter. This is not ideal as computing >>>> the value may be expensive. A function would allow the value to be computed >>>> lazily. >>>> >>>> >>>> >>>> References >>>> >>>> - [Dart] [Map.putIfAbsent]( >>>> https://api.dartlang.org/stable/2.0.0/dart-core/Map/putIfAbsent.html) >>>> >>>> - [Java] [Map.putIfAbsent]( >>>> https://docs.oracle.com/javase/8/docs/api/java/util/Map.html#putIfAbsent-K-V- >>>> ) >>>> _______________________________________________ >>>> es-discuss mailing list >>>> [email protected] >>>> https://mail.mozilla.org/listinfo/es-discuss >>>> >>> _______________________________________________ >>> es-discuss mailing list >>> [email protected] >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> _______________________________________________ > es-discuss mailing list > [email protected] > https://mail.mozilla.org/listinfo/es-discuss >
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

