archives

« Bugzilla Issues Index

#33 — Disabling 15.2.3.5-4-14 Object.create - argument 'Properties' is an Error object (15.2.3.7 step 2)


This test assumes that, at a maximum, Error objects have a set of own properties included in ['description', 'message', 'name']. This is in contradiction with Section 16:
"An implementation may provide additional types, values, objects, properties,
and functions beyond those described in this specification."

If an implementation decides to add an own property to all Error instances and that this property isn't a non-null object, the implementation will fail the test while it is allowed to add the property.

For this reason, I'd recommand to disable the test.

For the record, there is no mention of Error properties (own or inherited) which would be named 'description' or 'name'. Is there a reason why these properties have been redefined in the test?


Same for Test 15.2.3.5-4-37 for which Error instances could have other implementation-defined own non-object properties.


The test case reads as:
var props = new Error("test");
var result = false;
props.description = { value: 11 };
props.message = { value: 11 };
props.name = { value: 11 };


Object.defineProperty(props, "prop", {
get: function () {
result = this instanceof Error;
return {};
},
enumerable: true
});
var newObj = Object.create({}, props);
return result && newObj.hasOwnProperty("prop");


What if lines 3-5 were replaced by the more generic:
var tempNames = Object.getOwnPropertyNames(props);
for (var name in tempNames) {
name = tempNames[name];
props[name] = {value:11};
}


(In reply to comment #2)
> What if lines 3-5 were replaced by the more generic:
> var tempNames = Object.getOwnPropertyNames(props);
> for (var name in tempNames) {
> name = tempNames[name];
> props[name] = {value:11};
> }
Very interesting suggestion. I think it works.
Since we're dealing with an array, I would go more for something like:

(Object.getOwnPropertyNames(props)).forEach(function(name){props[name] = {value:11, configurable:true}});

A precondition to test for .forEach availability would need to be added.
I have added the "configurable:true" in case an implementation would already define a 'prop' property in Error. If it was the case, without the configurable true, we would make it not configurable and the Object.defineProperty would fail.


However, if an implementation was defining a non-configurable 'prop' property on Error objects, then... mmm... we're screwed aren't we?

So our solution is a good fix for now, but to be fully rigourous, we'd need a way to generate a property name which isn't already on an object.

Is there already such a function in the TestHarness?


(In reply to comment #3)
> (In reply to comment #2)
> > What if lines 3-5 were replaced by the more generic:
> > var tempNames = Object.getOwnPropertyNames(props);
> > for (var name in tempNames) {
> > name = tempNames[name];
> > props[name] = {value:11};
> > }
> Very interesting suggestion. I think it works.
> Since we're dealing with an array, I would go more for something like:
> (Object.getOwnPropertyNames(props)).forEach(function(name){props[name] =
> {value:11, configurable:true}});
> A precondition to test for .forEach availability would need to be added.
> I have added the "configurable:true" in case an implementation would already
> define a 'prop' property in Error. If it was the case, without the configurable
> true, we would make it not configurable and the Object.defineProperty would
> fail.
Done. The change will take place with the next IE Test Center-based updated to Test262.

> However, if an implementation was defining a non-configurable 'prop' property
> on Error objects, then... mmm... we're screwed aren't we?
I was thinking the same thing. An alternative would be to bail (successfully) if we find such a case.


I think I have a function that can help us out:
-----------------------------------
function unusedPropertyName(o){
var ownPropNames = Object.getOwnPropertyNames(o)

var unusedName = ownPropNames.reduce(
function(prev, curr, i){
var A = 'a', B = 'b';
var l = curr[i];
l = (l=== undefined || l !== A) ? A : B;

return prev + l;
}, '');

return unusedName;
}
-----------------------------------
We have an object. We get all its own property names. Based on that array, we create a string which, at index i has a letter that is different from the i-th letter of the i-th property name (it's kind of Kantor's diagonal method inspired).
At the end, we have a name which is different from all the property names currently on the object.

At some point, I was worried that the string could be too big (if there are too many properties), but I haven't seen any limitation on the spec about string length.

Array extras are just awesome. Love them :-) (first time I use .reduce for something useful)

Maybe that this function or some equivalent could be used in order to deal with implementation-independency issues of native objects properties ?

In our particular case, 'prop' could be replaced by a variable initialized with
unusedPropertyName(props) ?


Last night, I came up with another idea for the function.
One of the "issue" with the previous one is that if there are a lot of properties, the resulting string is going to be long and since it's concatenating strings, it's not very garbage-collector friendly (at least on Firefox, I don't know how other ES engines handle string garbage collection).

Here is the other idea:
-----------------------------------
function unusedPropertyName(o){
var ownPropNames = Object.getOwnPropertyNames(o)
// Get the length of the longest property name
var maxLen = ownPropNames.reduce(function(p, c){
return c.length>p? c.length : p;
}, 1);

// Return a string with a length which is maxLen+1
return Array(maxLen+1).map(function(){return 'a';}).join('');
}
-----------------------------------

Obviously, some combination of both approaches could be use.


(In reply to comment #6)
> return Array(maxLen+1).map(function(){return 'a';}).join('');
This doesn't work.

However, this does:
return Array(maxLen+1+1).join('a');
(the additional "+1" is because join adds the array.length -1 separator)