Re: Array-with-item in WebIDL

On 6/23/15, Adam Klein <adamk@chromium.org> wrote:

Hi Adam –

> On Mon, Jun 22, 2015 at 9:04 PM, Alex Russell <slightlyoff@google.com>
> wrote:
>>
>> On Wed, Jun 17, 2015 at 8:59 AM, Jonas Sicking <jonas@sicking.cc> wrote:
>>
>>> FWIW, very few of the DOM APIs return array-like objects with a
>>> "contains" function. It's much more common to return an object with a
>>> "item" function. So if we were able to add "item" but not "contains"
>>> that would still enable us to switch most of the APIs in question [*]
>>> to use real JS Arrays.
>>>
>>> I'd also love to hear some thoughts about what we want Array.isArray()
>>> to return for one of these objects. And would using a subclass of
>>> Array accomplish that desired behavior?
>>>
>>> [*] Sadly NodeList is not one of the APIs in question since NodeList
>>> needs to not be mutable through any Array mutator functions, but can't
>>> use a frozen Array since it changes its contents. Fortunately NodeList
>>> is an exception here.
>>
>>
>> I don't think that's strictly true. NodeList changes *from the C++ side*
>> are
>> in fact reflected to others with references today, but the reverse is not
>> true. Mutating an Array which represents this contents doesn't
>> necessarialy
>> need to reflect back to the C++ side, and because the contents (from the
>> perspective of script) are updated by C++ at random points, they can be
>> re-set by the C++ side whenever.
>>
>> NodeList can be an Array, it's just that the mutating methods need to not
>> propagate back.
>>
>
> I don't understand how you'd see this working. Are you saying that author
> code could be allowed to mutate NodeLists but that those mutations would be
> overwritten later by C++? That seems like a very strange API:
>
> var div = document.createElement('div');
> var span = document.createElement('span');
> var childNodes = div.childNodes;
> div.appendChild(span);  // childNodes[0] is now span
> var span2 = document.createElement('span');
> childNodes[0] = span2;  // what is childNodes[0] now? span2?
> div.appendChild(span2); // what's in childNodes now? maybe span2 twice?
>

Exactly. And that doesn't even get into the issues with the special
[[DefineOwnProperty]] (formerly called [[Put]]) on Array instances,
where indexed properties can modify the length, and vice-versa.

I mentioned SELECT elements earlier. That object's interesting for
another reason: Its [[DefineOwnProperty]] actually modifies the DOM,
which is reflected in its childNodes, `options` — adding and removing
OPTION elements. It's been this way since Netscape 4.

 var s = document.createElement("select");
 s.length = 10;
 s.childNodes = [0];

In order to usurp that little issue, you'd have to either

1) Have an internal [[Thaw]] or some other such design to temporarily
allow internal code to override the frozenness of the array. That way,
the browser could still modify the collection and programs still
wouldn't be able to.

2) Not make it an array.

3) Recap on the initial problem and go back to the drawing board.

DOM collections (NodeList, HTMLCollection, et al) might be redesigned
to have Array.prototype interposed in the prototype chain. But they
couldn't have Array [[DefineOwnProperty]].  So they could not per se
be Array instances. Because adding array indexed properties can modify
its length and vice-versa.

ES6 says array instances are instances are Array exotic objects. And
to these objects it defines a [[DefineOwnProperty]] method that is
incompatible to the NodeList (et al).

Currently, browsers don't modify the length of the NodeList here:

 document.childNodes[2] = 7;

Nor do they remove indexed properties here:

 document.childNodes.length = 0;
-- 
Garrett
@xkit
ChordCycles.wordpress.com
garretts.github.io
personx.tumblr.com

Received on Tuesday, 23 June 2015 16:27:21 UTC