On May 7, 2010, at 12:15 PM, Allen Wirfs-Brock wrote:
> I don’t think it is valid to use Object.keys as part of your definition of
> for-in because that leaves you with a circular definition as the
> specification for Object.keys says it orders the keys in the same order used
> by for-in.
I wasn't meaning to use this as a spec worthy definition, but as a way to see
how for in was evaluated across object and it's prototypes.
> Ignoring algorithms for the moment and simply looking at semantics, I don’t
> see how your interpretation makes any sense at all. The semantics of
> prototype inheritance creates the illusion that inherited properties are part
> of the inheriting object unless they are explicitly over-ridden by an own
> property. The semantics you describe break this illusion by essentially
> allowing the [[enumerable]] attribute of an inherited property to over-ride
> the [[enumerable]] attribute of a same-named own property. This is
> essentially the same mistake that the JScript has historically made with
> ES1-3 when it allowed an inherited dontenum attribute to suppress the
> enumeration of a like-name own property. I think there is universal
> agreement that JScript was wrong in this regard. What you are proposing is
> equally wrong but with the boolean value of the attribute reversed.
This isn't a proposal, this is what we do, and we do it this way because in the
past our failure to do so broke sites.
> I believe that the correct list of enumerated names for for-in (in the
> absence of side-effects that modify properties or property attributes) is:
> ...<snip>...
> This is also the list of names that Object.keys should produce. The actual
> order of the names in the result of the above function is not specified by
> ES5. The prose of 12.6.4 (but not the algorithm) concerning deleted
> properties means that side-effects that delete properties should be handled
> as if for-in was then implemented as:
>
> getEnumerableNames(obj).forEach(function(n) {if (n in obj)
> execute-for-in-body-with-n});
object.keys only returns own properties -- it doesn't return the properties of
the prototype.
> But note that since the order is undefined, if the body does any deletes
> there is no guarantee whether you will or won’t see a key that is subject to
> deletion. The only guarantee is that if all occurrences of a particular
> property name (there may be multiple along the prototype chain) are deleted
> before processing that name, then the for-in body will not be execute for
> that name.
> Things are even more unspecified if properties are added as side-effects or
> if enumerable attribute values are dynamically changed.
It seems a bug in the spec that this isn't defined -- the order of enumeration
of own properties in actual implementations is the order of addition, it has to
be this or sites will break. JSC originally followed the ES3 spec (which
didn't defined ordering) and sites broke. This is the set of constraints the I
know are necessary:
1. Order of enumeration of own properties is the order of addition
2. You can't enter the loop with a property that has been added since the start
of iteration
3. You can't enter the loop with a property has been removed since that start
of iteration
4. You can't enter the loop with the same value multiple times
Sites break if you don't enforce any one of these constraints. We know this
because the behaviour of iteration in JSC has been specifically implemented to
enforce these constraints as a result of re-world site breakage.
It should be easy to see how each of these constraints is enforced in the
example code i listed earlier.
The place where there has historically been a difference between
implementations is precisely what happens with properties from the prototype
chain.
--Oliver_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss