This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 26985 - Remove requirement for prose around iterable<> if object has indexed properties
Summary: Remove requirement for prose around iterable<> if object has indexed properties
Status: NEW
Alias: None
Product: WebAppsWG
Classification: Unclassified
Component: WebIDL (show other bugs)
Version: unspecified
Hardware: PC All
: P2 normal
Target Milestone: ---
Assignee: Cameron McCormack
QA Contact: public-webapps-bugzilla
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-10-06 12:11 UTC by Anne
Modified: 2015-10-19 16:51 UTC (History)
6 users (show)

See Also:


Attachments

Description Anne 2014-10-06 12:11:30 UTC
E.g. NodeList and DOMTokenList both have indexed property getters. Their iterator should work the same way. It seems we should default to the prose for indexed property getters (as we already do for getting Symbol.iterator, see bug 26984) and perhaps allow that to be overridden (if someone can make a case for that).

Of course, ideally new objects do not use indexed property getters so that seems unlikely we would have such cases.
Comment 1 Boris Zbarsky 2014-10-06 12:23:53 UTC
Basically, the proposal is that http://heycam.github.io/webidl/#es-iterators would go something like this:

  If the interface defines an indexed property getter, then the Function object
  is %ArrayProto_values% ([ECMA-262], section 6.1.7.4).

  If the interface has an iterable declaration and does not define an indexed
  property getter, ...

  If the has a maplike declaration or setlike declaration and does not define
  an indexed property getter, ...

That would actually make sense with the prose at http://heycam.github.io/webidl/#dfn-values-to-iterate-over which defines "values to iterate over" for the indexed case.  We'd still need to modify whatever methods iterable<> pulls in that assume the "default iterator" to work with the indexed case, though (e.g. forEach() would just work, but keys() would need some changes.

I think this change is fine; people are unlikely to want iterable things with indexed getters that iterate something other than the indices, and I _really_ hope people don't start adding maplike/setlike things with indexed getters.

Maybe that hope should even be codified by making that invalid IDL?
Comment 2 Boris Zbarsky 2014-10-06 12:29:54 UTC
That said, I looked more carefully at web idl today and it looks like the current behavior is in fact well-defined in that:

1)  If you have an indexed getter and iterable<> then your value set is your indexed values (this is defined in the non-ES-specific section of the spec).

2)  The ES section makes this work by requiring the use of something other than the Array iterator in this case.

I think #2 is a bug we should fix, but #1 means there is in fact no need for prose defining the value set when setting iterable<> on an interface with indexed props
Comment 3 Domenic Denicola 2014-10-06 13:48:16 UTC
I don't think I've said it yet on these bugs so popping in here to say +1 for re-using %ArrayProto_values% by setting IndexedGetterClass[Symbol.iterator] = %ArrayProto_values%.
Comment 4 Boris Zbarsky 2015-10-18 15:12:09 UTC
So the fact that putting a single-type iterable decl on DOMTokenList, say, means keys() will produce the same thing as values() (per planned spec changes; see <https://bugzilla.mozilla.org/show_bug.cgi?id=1215925#c2>) is broken imo.

I think the right thing to say is that for the case of indexed props and iterable<> the following apply:

1)  Either the iterable<> declaration needs to take no type or its type must match the type of the indexed getter.

2)  keys/values/entries should use CreateArrayIterator or just be set to the relevant Array.prototype functions.

3)  forEach should perhaps also be Array.prototype.forEach.

But really, it would be simpler to make the class [LegacyArrayClass] (which is legacy why again?), because then you get all of the above for free, plus map() and filter().  Why is this not a superior approach?
Comment 5 Boris Zbarsky 2015-10-18 15:18:55 UTC
I guess @@isConcatSpreadable support is needed to make more things LegacyArrayClass.  But that seems like an implementation issue, not a spec problem...
Comment 6 Anne 2015-10-18 16:09:15 UTC
keys() matching values() is exactly what ECMAScript does too.
Comment 7 Boris Zbarsky 2015-10-18 16:22:55 UTC
> keys() matching values() is exactly what ECMAScript does too.

Not for arrays, as far as I can tell: [...["abc", "def"].keys()] is [0, 1] but  [...["abc", "def"].values()] is ["abc", "def"].

At least based on reading the spec.  In actual implementations, https://esdiscuss.org/topic/array-prototype-values-is-not-web-compat-even-with-unscopables is a bit of a problem, I guess.  :(
Comment 8 Boris Zbarsky 2015-10-18 16:25:28 UTC
And in Chrome, for |<body class="foo">|, [...document.body.classList.keys()] is [0], not ["foo"].
Comment 9 Boris Zbarsky 2015-10-18 16:27:58 UTC
Implementations could work around (temporary?) lack of Array.prototype.values by defining .values mapping to a CreateArrayIterator thing directly on the prototypes of indexed things with iterators.  Those could then be removed, hopefully, if/when Array.prototype.values becomes a thing.
Comment 10 Anne 2015-10-18 16:48:00 UTC
DOMTokenList is not an Array-equivalent though, it's a Set-equivalent. (The "List" is misleading.)
Comment 11 Domenic Denicola 2015-10-18 17:05:47 UTC
Right. This is precisely a question of Set-like vs. Array-like. DOMTokenList does seem a lot more Set-like to me. That's why it used single-type iterable; that's what single-type iterable is for, in fact.

(I think it's weird TC39 decided to add keys() and entries() to Sets. But they did.)
Comment 12 Boris Zbarsky 2015-10-18 17:06:59 UTC
If it's a Set-equivalent, why does it have an indexed getter and a .length?  It sure quacks like an array when read, though I agree the behavior on _mutations_ isn't very arraylike.

Maybe we would have _liked_ to ship a setlike interface here, but the arraylike thing has been implemented for a while now, so we're kinda stuck with it.

More importantly, the rules for iterable-and-indexed-props need to make sense in general for indexed things, no matter what weirdness we have with DOMTokenList.
Comment 13 Anne 2015-10-19 08:05:35 UTC
Well, Set came later and did s/length/size/. And getters went out of fashion (which is why we should rename all of them "legacy" in IDL as per some other bug).

Maybe instead of keying of indexed getters we could make it explicit what ECMAScript type the class is an equivalent of?
Comment 14 Boris Zbarsky 2015-10-19 13:28:14 UTC
We already have ways of expressing that something is like a Set: setlike, no?  DOMTokenList doesn't seem to be using it...
Comment 15 Anne 2015-10-19 16:43:18 UTC
setlike<> doesn't work since it adds more than just iteration features. It seems the main problem with DOMTokenList is that it has an indexed getter as well, which changes the behavior we'd ideally want.

Cameron, Domenic, any thoughts on what would be best here? Should there be a feature in IDL to override the presence of indexed getters from it being treated as an Array?
Comment 16 Boris Zbarsky 2015-10-19 16:44:39 UTC
> setlike<> doesn't work since it adds more than just iteration features.

Yes, but are those a problem in this case?
Comment 17 Domenic Denicola 2015-10-19 16:47:25 UTC
I would be OK with saying that since this has indexed getters it is more array-like than set-like, despite how it behaves under mutations. An unfortunate accident of historical evolution.

Without the set-like properties and methods (size, add, has, delete), it does seem strange for the iteration to behave like a set.
Comment 18 Anne 2015-10-19 16:51:03 UTC
(In reply to Boris Zbarsky from comment #16)
> Yes, but are those a problem in this case?

That would add clear, and delete. delete could be an alias of remove. clear would be new functionality. Neither seems actively harmful and it might even be good so I'm not opposed. We could even add size as an alias for length.

Domenic?