Re: Non-constructible constructors and Arrays

On Jul 28, 2011, at 7:25 PM, Jonas Sicking wrote:

> On Thu, Jul 28, 2011 at 7:12 PM, Allen Wirfs-Brock
> <allen@wirfs-brock.com> wrote:
>> 
>> On Jul 28, 2011, at 5:04 PM, Jonas Sicking wrote:
>> 
>>> As I asked above, what would the mutating functions do to "live"
>>> NodeList? And IMHO only APIs that want to return "live" objects should
>>> return NodeLists. Others should simply return arrays.
>>> 
>>> 
>> 
>> In ES5 all of the Array.prototype functions are defined to operate upon generic objects with "array indexed" (ie, integer string values) properties. The objects they operate upon do not need to be Array instances. The functions are specified in terms of the basic ES5 internal operations such as [[Get]], [[Put]],  etc.  Such generic objects (or even Array instances for that matter) may, in ES5, have non-writable and non-deletable properties and the objects may be non-extensible.  For that reason, the array algorithms all explicitly define how to deal with such situations.  Generally, they throw when they try to modify a property in a manner that is forbidden for that object.
>> 
>> If a DOM implementation provides reasonable implementations of [[Get]], [[Put]] and friends then the Array functions should just work on its DOM objects. Trying to reverse a read-only DOM object may not do anything useful, but its unuseful behavior would still be fully specified.
> 
> I'm very aware how the Array functions are defined. The problem is
> that there aren't any reasonable defaults we could provide for
> NodeList's [[Put]] operations simply due to what a NodeList
> represents.
> 
> The only reasonable thing we could do is to make all mutating
> operations throw, which frankly would be a pretty strange API. I.e.
> all NodeLists would have whole host of operations like .push and
> .shift which always would throw. It would seem much better if those
> operations weren't there.

Such an implementation would be no different from what happens if somebody does something like:

var aReadOnlyArray = Object.freeze([1,2,3,4,5,6,7,8,9,10]);

and then called various array methods on aReadOnlyArray.  The methods that would work include:

aReadOnlyArray.toString()    // returns a string containing the string representation of the  elements, comma separated
aReadOnlyArray.toLocaleString()
aReadOnlyArray.concat(11,12,13)   //return a new array containing 1,2,3,4,6,7,8,9,10,11,12,13.  NodeList would also produce a array, not a NodeList
aReadOnlyArray.join("+")   //return "1+2+3+4+5+6+7+8+9+10"
aReadOnlyArray.slice(-3)  //return [8,9,10]
aReadOnlyArray.indexOf(3)    //return 2
aReadOnlyArray.lastIndexOf(8)  //return 7
aReadOnlyArray.every(function (e) {return typeof e == 'number'})   //return true
aReadOnlyArray.some(function (e) {return e > 10})   //return false
aReadOnlyArray.forEach(function (e) {alert(e)})  
aReadOnlyArray.map((function (e) {return -e})    //return [-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]
aReadOnlyArray.filter((function (e) {return e>5})    //return [6,7,8,9,10]
aReadOnlyArray.reduce(function(prev,cur) {return prev+cur}) // return 55
aReadOnlyArray.reduceRight(function(prev,cur) {return prev-cur}) // return -35

The methods that would throw an exception are:
aReadOnlyArray.pop()
aReadOnlyArray.push(11,12)
aReadOnlyArray.reverse()
aReadOnlyArray.shift()
aReadOnlyArray.sort()
aReadOnlyArray.splice(2,3,-3,-4,-5)
aReadOnlyArray.unshift(0,-1,-2)

So, if a NodeList acted in this manner, it would still have more useful methods than ones that would throw and the failures that would occur are exactly the same the occur for pure JavaScript readonly arrays.

> 
> This discussion has come up a number of times and the conclusion is
> always the same. Several solutions have been proposed, some more
> workable than others, but unfortunately this thread doesn't mention
> any of them, nor does it bring up any new information which would help
> us get any closer to a conclusion.

see above

Allen

Received on Friday, 29 July 2011 05:35:12 UTC