Default value argument for Map/WeakMap.prototype.get()
it was there and it has been removed ... curious to see if it will be back.
Said that, same way you do
obj.prop = obj.prop || def;
you can do
obj.set(prop, obj.get(prop) || {});
I know it's not the equivalent since you might want to be able to set null, false, "", NaN, etc etc ... but it's easy to add utilities to current logic while it might be ambiguous to change defaultValue behavior later on.
As example, I might want to consider an inherited property as valid value while what you are suggesting, in a more generic approach, is not considering inheritance because the property is not "own"
br
if interested, just because I need to uncomment a line if something will ever change here: WebReflection/es6-collections/blob/master/build/es6-collections.js#L48
before it was as you asked already. Many emails on this after :-/
Using substack/defined you can do
var d = require("defined"); var x = d(m.get("key"), defaultValue);
Not sure if this is an argument for adding default value because this module is so ridiculous ... or against it since it’s so trivial to get the functionality yourself.
From: Andrea Giammarchi Sent: November 28, 2012 14:27 To: Jason Orendorff CC: es-discuss Subject: Re: Default value argument for Map/WeakMap.prototype.get()
it was there and it has been removed ... curious to see if it will be back.
Said that, same way you do
obj.prop = obj.prop || def;
you can do
obj.set(prop, obj.get(prop) || {});
I know it's not the equivalent since you might want to be able to set null, false, "", NaN, etc etc ... but it's easy to add utilities to current logic while it might be ambiguous to change defaultValue behavior later on.
As example, I might want to consider an inherited property as valid value while what you are suggesting, in a more generic approach, is not considering inheritance because the property is not "own"
br
On Wed, Nov 28, 2012 at 11:07 AM, Jason Orendorff <jason.orendorff at gmail.com<mailto:jason.orendorff at gmail.com>> wrote:
I propose adding an optional second argument to the .get() method on Map and WeakMap.
Map.prototype.get(key[, defaultValue])
The default value would be returned only when the given key is not in the map. That is, in the last step of the spec for these two methods, instead of "Return undefined", it would say "Return defaultValue".
Python and Ruby have this. (In Ruby it's called "fetch".) It's handy in cases like:
var counts = new Map;
for (let word of words)
counts.set(word, counts.get(word, 0) + 1);
thing is ... it's not really that trivial.
What if you decide to define a property/value as undefined ?
In this case the equivalent is, AFAICT
function d(map, key, defaultValue) { return map.has(key) ? map.get(key) : defaultValue; }
so that
counts.set(word, d(counts, word, 0) + 1);
the fact is that map.set({}, undefined) is allowed/valid so it's easy to go down to ambiguity
var m = new Map; m.set(m, undefined); m.has(m); // true
br
apologies, I meant it is trivial, but it depends what you are looking for / need
So, since is that easy to create your own case, then no reason to add the default argument in the API
On Wed, Nov 28, 2012 at 12:12 PM, Andrea Giammarchi <andrea.giammarchi at gmail.com> wrote:
apologies, I meant it is trivial, but it depends what you are looking for / need
So, since is that easy to create your own case, then no reason to add the default argument in the API
No, that's not the case. Even if it's "trivial" to write it on your own, if its use-case is sufficiently common, adding it helps with the overall usability of the language. After all, by your argument, we don't need Map#has either, since you can get around it by just doing:
function mapset(map, key, val) { map.set(key, [val]); } function mapget(map, key) { return map.get(key)[0]; } function maphas(map, key) { return map.get(key) === undefined; }
This lets you store undefined in a map, and still distinguish it from the key not being set at all, while using solely Map#get and Map#set, and a trivial bit of code.
In this case, I agree that getting a default value from a map when the key is undefined is extremely common (I do it regularly when using dictionaries in Python), and it should be part of the default API.
Agreed.
Allen, did this default optional parameter to get() get dropped by accident?
has is another story and your functions will fail. I have provided already this example which is perfectly valid:
var m = new Map; m.set(m, undefined); m.has(m); // true
all you need in JS, which is not Python, is the ||
m.get(key) || defaultValue
which is the most common case, as you wrote, for maps.
I strongly doubt you gonna store false, empty strings, or null as values, right?
It's funny I am the first one shouting that
obj.prop = obj.prop || defaultValue
is not a good pattern but here you want a better one for Map.prototype
It's also funny I have already implemented that and it is not me pushing back so ... I actually don't get anything you said or what you think I wrote :-/
br
it's also like this in the wiki: harmony:weak_maps#alternate_spec_based_on_ff6.0a1
It isn't in the wiki proposal, so it probably didn't get included when I created those chapter 15 sections. If there is consensus on those optional arguments I can add them.
Good, so now my only concern is about the fact ternary or || is better for GC and performance, i.e.
var query = map.get('queried', $('myquery'));
If you repeat above example code 100 times, for 100 times you'll re-query the DOM. I might be the only one here but I can see already abuses of this second argument.
This is as example not true using the ternary or the || operator
var query = map.has('queried') ? map.get('queried') : $('myquery');
// or quick and dirty var query = map.get('queried') || $('myquery');
but in both cases $('myquery') is performed many times because there's no shortcut able to set and return values, which is eventually the next logic thing to change to this API.
What I believe is equivalently needed is a set method that returns the set value so that
var query = map.has('queried') ? map.get('queried') : map.set('queried', $('myquery'));
// or quick and dirty var query = map.get('queried') || map.set('queried', $('myquery'));
in both cases the $('myquery') will be invoked only once, accordingly with the fact it's returning an object and not a falsy value.
This is also much more familiar for developers that are used to write such code:
var query = obj.queried || (obj.queried = $('myquery'));
This is in my opinion the best practice while, going back to the beginning of this reply, the extra argument to the get() method will bring to developers a bad pattern, IMHO
- it's easy to forget to store it later
- it executes eventually the expensive assignment/procedure regardless the key is present or not
At least point 1 could be solved with a third argument, false by default, able to store automatically the defaultValue if missing.
map.get('queried', $('myquery'), true).each(whatever);
Above example will ensure that map.get('queried') next time will return the very first defaultValue that has been stored ...
Here, a universe of ambiguity created by a second argument that more I write about it, less makes sense even if handy.
My 2 cents
On Wed, Nov 28, 2012 at 1:16 PM, Andrea Giammarchi <andrea.giammarchi at gmail.com> wrote:
has is another story and your functions will fail. I have provided already this example which is perfectly valid:
var m = new Map; m.set(m, undefined); m.has(m); // true
...what? Why would my functions fail? Assuming you use them instead of the built-in map functions, they work just fine.
all you need in JS, which is not Python, is the ||
m.get(key) || defaultValue
which is the most common case, as you wrote, for maps.
This fails if the value is 0, null, false, undefined, or any other falsey value.
I strongly doubt you gonna store false, empty strings, or null as values, right?
It's completely reasonable to store those things, and I have done exactly that when using dictionaries in languages like Python and Lisp.
It's also funny I have already implemented that and it is not me pushing back so ... I actually don't get anything you said or what you think I wrote
You said (paraphrasing, obviously) "there's no need to add this feature, because authors can just add a one-line function that accomplishes it". I was just responding that this is a bad argument; while the ease of coding it yourself is a relevant factor, it's not the only one, as one should also consider how often it'll be used.
right, I have explained my concern better in my latest reply.
br
I propose adding an optional second argument to the .get() method on Map and WeakMap.
The default value would be returned only when the given key is not in the map. That is, in the last step of the spec for these two methods, instead of "Return undefined", it would say "Return defaultValue".
Python and Ruby have this. (In Ruby it's called "fetch".) It's handy in cases like: