This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.
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.
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?
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
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%.
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?
I guess @@isConcatSpreadable support is needed to make more things LegacyArrayClass. But that seems like an implementation issue, not a spec problem...
keys() matching values() is exactly what ECMAScript does too.
> 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. :(
And in Chrome, for |<body class="foo">|, [...document.body.classList.keys()] is [0], not ["foo"].
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.
DOMTokenList is not an Array-equivalent though, it's a Set-equivalent. (The "List" is misleading.)
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.)
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.
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?
We already have ways of expressing that something is like a Set: setlike, no? DOMTokenList doesn't seem to be using it...
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?
> setlike<> doesn't work since it adds more than just iteration features. Yes, but are those a problem in this case?
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.
(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?