Map and Set constructors should take a single optional iterable argument

RESOLVED FIXED in mozilla13



JavaScript Engine
6 years ago
5 years ago


(Reporter: jorendorff, Assigned: jorendorff)


Other Branch

Firefox Tracking Flags

(Not tracked)



(1 attachment, 2 obsolete attachments)



6 years ago
Set(iterable) should effectively do this:

    for (let v of iterable)

Likewise, Map(iterable) should do this:

    for (let [k, v] of iterable)
        the_new_map.set(k, v);

A nice thing about this is that if we also make Map iteration yield pairs, then it provides a fairly nice way to make a copy of a Map or set:

    new Map(oldmap)
    new Set(oldset)

None of this has been mentioned in TC39 or even on es-discuss.

Comment 1

6 years ago
Created attachment 596218 [details] [diff] [review]

needs more tests
Assignee: general → jorendorff

Comment 2

6 years ago
Created attachment 596329 [details] [diff] [review]
Attachment #596218 - Attachment is obsolete: true
Attachment #596329 - Flags: review?(luke)

Comment 3

6 years ago
For dherman:

From an API design perspective, there are two things I'm mildly uncertain about:

1. Another reasonable thing folks might want is for
    Map({x: 1})
to produce a Map with .get("x") === 1. Currently it just throws.

We can maybe satisfy that need with a helper:
    Map.fromProperties({x: 1})
or perhaps:
    import * from "@inspect";
    Map(properties({x: 1}))

Or else Allen's object reform ideas which I still haven't looked at.

2. This is not very strict about the input. Map(DATA) behaves exactly like:
    m = Map();
    for (let [k, v] of DATA)
        m.set(k, v);
and destructuring is quite lenient. So all these errors pass silently:
    // A string can be a pair
    Map(["hello"])              // ===> #{"h" => "e"}#

    // An object that clearly isn't a pair can be a pair
    Map([{}])                   // ===> #{undefined => undefined}#

    // Simpsons nuclear fish case: a triple can be a pair
    Map([[key, value, blah]])   // ===> #{key => value}#

But if this is a flaw, it is a flaw in destructuring, not this patch per se.

Comment 4

6 years ago
Created attachment 596472 [details] [diff] [review]

Fix OOM reporting in AddToMap and AddToSet.
Attachment #596329 - Attachment is obsolete: true
Attachment #596329 - Flags: review?(luke)
Attachment #596472 - Flags: review?(luke)

Comment 5

6 years ago
Comment on attachment 596472 [details] [diff] [review]

Review of attachment 596472 [details] [diff] [review]:

r+ on the JS implementation side assuming you flag brendan/dherman/allen for an API review.  I dare say my JS cultural knowledge is weak.  (On the subject, though: I naively expected Map(obj) to map obj's properties to values.  On further reflection, though, I see why arrays are preferable so I like the Map.fromProperties idea.)

Beautiful patch; one request:

::: js/src/builtin/MapObject.cpp
@@ +250,5 @@
> +    CallArgs args = CallArgsFromVp(argc, vp);
> +    Value arg = (argc > 0 ? args[0] : UndefinedValue());
> +    if (!arg.isUndefined()) {
> +        if (!ForOf(cx, arg, AddToMap(map)))

This "if we have an arg and it isn't undefined" pattern seems to come up a lot and always leads to predicates like this.  It seems like we could add a 'hasDefined(n)' that lets us write:

  if (args.hasDefined(0) && !ForOf(cx, args[0], AddToMap(map))
      return false;

A quick grep for /arg.*isUndefined/ shows 20 or places that could use this!
Attachment #596472 - Flags: review?(luke) → review+

Comment 6

6 years ago
Dave Herman and Mark Miller are OK with this API, at least provisionally. (Mark is the design lead for this feature in TC39.) Of course we'll implement whatever TC39 settles on in the end.

Follow-up bug for hasDefined is coming up.

Comment 7

6 years ago
Filed bug 730676 with patch.

Comment 8

6 years ago

Bug 730676 will land shortly; apparently one of these patches I'm trying to land has a small Linux-only, valgrind-only bug that I'm still trying to track down.
Last Resolved: 6 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla13
You need to log in before you can comment on or make changes to this bug.