Closed Bug 726223 Opened 11 years ago Closed 11 years ago

Map and Set constructors should take a single optional iterable argument


(Core :: JavaScript Engine, defect)

Other Branch
Not set





(Reporter: jorendorff, Assigned: jorendorff)



(1 file, 2 obsolete files)

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.
Attached patch WIP 1 (obsolete) — Splinter Review
needs more tests
Assignee: general → jorendorff
Attached patch v2 (obsolete) — Splinter Review
Attachment #596218 - Attachment is obsolete: true
Attachment #596329 - Flags: review?(luke)
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.
Attached patch v3Splinter 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 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+
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.
Filed bug 730676 with patch.

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.
Closed: 11 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla13
You need to log in before you can comment on or make changes to this bug.