Re: indexed properties on NodeLists and HTMLCollections

On May 5, 2011, at 5:52 PM, Boris Zbarsky wrote:

> On 5/5/11 7:17 PM, Allen Wirfs-Brock wrote:
>> But native JS objects can also dynamically mutate in apparently arbitrary ways:
> 
> Yes, but "apparently" is the key part here.
> 
>> var myGlobal = { };
>> alert(myGlobal.toString);  //built-in toString function
>> callSomeFunctionIdontKnowMuchAbout();
>> alert(myGlobal.toString);   //displays some other value because a toString property was added to the myGlobal obj by the function
>> callAnotherFunctionIdontKnowMuchAbout();
>> alert(myGlobal.toString);  //built-in toString function because the function deleted the property the new toString property from the obj
> 
> Yes, but for this to happen the functions you call have to know something about myGlobal.  There's no weird side-channel mechanism where a function call suddenly defines hundreds or thousands of own properties on all sorts of objects, including objects that it can't reach directly (because they're only present in closure scopes).

but the object that is being modified can be and is reachable indirectly. That fact that changes can be observed to occur proves that it is reachable.  Also, if there isn't a reference path to the object, it couldn't be observed in which cases any changes to the object would be irrelevant.

>  With the way DOM nodelists are supposed to work there IS such a side-channel mechanism.

There is nothing special about this side-channel. It is just normal object reference semantics. However, the example I choose maybe didn't make that point clear. Here is a better example,

function f() {
   var myLocal = callSomeFunctionIDidntWriteThatReturnsSomeObject();
   alert(myLocal.toString);  //built-in toString function
   callSomeOtherFunctionIDidntWrite();
   alert(myLocal.toString);   //displays some other value because a toString property was added to the myGlobal obj by the function
   callAnotherFunctionIdontKnowMuchAbout();
   alert(myLocal.toString);  //built-in toString function because the function deleted the property the new toString property from the obj
}();

Anytime you obtain access to an object from another source, there is the possibility that the source may have retained a reference to the same object and/or made a reference available to other third parties.  Subsequently anytime controls pass out of a known code block there is a possibility that control flow will reach one of these third parties that have a reference to the original object.  They may dynamically update the state of the original object.  From the perspective of function f, the object referenced as myLocal simply appears to have dynamically mutated.

This is exactly what happens with NodeLists and other DOM object.  You can replace (either directly or indirectly)  the "CallSome..." calls with appropriate DOM  calls and exactly this sort of behavior will occur.

There is nothing unique or special about the DOM in this regard.  Any object model can be built with exactly this same semantics.
> 
>> The only way for a JavaScript programmer to ensure this doesn't happen is via Object.seal, etc.
> 
> That's just not true.  Consider this testcase:
> 
>  function foo() {
>    var obj = {};
>    return function mutator() { /* do something with obj */ }
>  }
>  var f = foo();
> 
> Now the JS programmer is guaranteed that there will be no bizarre mutations of |obj| that are not explicitly caused by mutator.

Yes, but this is a different type of example (and the reason I used a global variable in my original example).  obj is only safe from mutation because it was created by a primitive language mechanism and is never passed out of the local lexical scope.  This is not how NodeLists are created. NodeList come from an agent who may have retained a reference (and based upon observable behavior apparently do retain such a reference.)


More in a separate message.

Allen

Received on Friday, 6 May 2011 06:23:09 UTC