"for-in", shadowing and deleting properties.

Gareth Smith gds at doc.ic.ac.uk
Thu May 9 03:48:40 PDT 2013


Andrea: Thanks for your quick reply!

I think I understand what you just told me, but would like to clarify to
be sure: Am I right in thinking that you believe that to correctly
interpret the for-in/Ennumerate section of the spec/draft (ES5:12.6.4 ,
ES6:8.3.12) we should treat the phrases "property" and "property name"
as interchangeable in those sections?

I certainly think I agree with the good sense of making an
implementation behave the way you have described, but am particularly
interested in exactly what is and isn't expressly forbidden by the
published standard.

I think you're telling me that if I write an implementation which
chooses to skip the enumeration of x in either of my original examples,
I will be in violation of the published standard. What I'm trying to
understand now is how I should read the letter of the standards
documents in order to arrive at this conclusion. Am I right in thinking
that the phrases "property" and "property name" should be treated
interchangeably in these sections, or is there some other phrasing or
implied intent that I've misunderstood?

Should I submit versions of my original two examples as test262 cases,
which check that x definitely is enumerated?

I apologise for the unusual slant of my questions. I'm not writing an
ECMAScript implementation (not one intended for deployment anyway), nor
am I asking exclusively about the behaviour of existing
implementations. I'm part of an academic effort to formalise the
existing specification in the Coq proof assistant, so I am forced to
care about the detail of which particular implementation behaviours are
allowed or disallowed by which particular phrases in the published
standard. If we can't pin these behaviours on particular phrases in the
published standard, then I'm very interested in existing community
consensus.

Thanks again!

Gareth.

Andrea Giammarchi <andrea.giammarchi at gmail.com> writes:
> in the Example 1 you simply loop over all keys in the chain, included the x
> inherited from b.
>
> The fact you shadow that is irrelevant, it was there in any case.
> The fact you get 1 in the log is because you access the shadowed property
> through a[i] so expected result.
>
> You are doing a for/in, not a for/of
>
> In the second Example is the same, for/in loops over all enumerable
> properties in the chain, it does not matter what you do with the current
> instance if that property name is inherited so, once again, expected.
>
> var b = { x : 2 },
>     a = { y : 0, __proto__ : b },
>     k;
>
> for (k in a){
>     alert(k + ": " + a[k]);
>     delete b.x; // note: it's b, not a
> }
>
> this will loop only over a.y skipping x
>
> If you want to be sure about having a keys snapshot of the own properties,
> you can, in ES6:
>
> let b = {x: 2},
>     a = {y: 0, __proto__: b},
>     k;
>
> for (k of Object.keys(a)) {
>   console.log(k);
> }
>
> or an equivalent for loop/iteration over keys such
>
> Object.keys(a).forEach(function(k){
>   this[k]; // whatever
> }, a);
>
> br
>
>
>
> On Wed, May 8, 2013 at 11:16 AM, Gareth Smith <gds at doc.ic.ac.uk> wrote:
>
>> Hello,
>>
>> I hope this is the right place to ask this question - please let me know
>> if not!
>>
>> I am trying to understand the specification of for-in, both for ES5 and
>> for ES6, and in particular the interaction between shadowing and adding
>> or deleting properties. Here are the parts of the ES5 spec and ES6 draft
>> that seem most relevant:
>>
>> ES5: http://www.ecma-international.org/ecma-262/5.1/#sec-12.6.4
>> ES6: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-8.3.12
>>
>> Here are two motivating examples. In both examples, I'll assume that 'y'
>> is enumerated first. For each example, the question is: does the
>> specification require 'x' to be enumerated, or can an implementation
>> choose to skip it?
>>
>> Example 1:
>>
>> var b = { x : 2 }
>> var a = { y : 0, __proto__ : b }
>>
>> for (i in a){
>>     console.log(i + ": " + a[i]);
>>     a.x = 1
>> }
>>
>> In this first example b.x becomes shadowed by a.x before being
>> enumerated. Thus we have both "If new properties are added to the object
>> being enumerated during enumeration, the newly added properties are not
>> guaranteed to be visited in the active enumeration" and "a property of a
>> prototype is not enumerated if it is “shadowed” because some previous
>> object in the prototype chain has a property with the same name."
>>
>> Does the specification allow us to skip 'x'?
>>
>> Example 2:
>>
>> var b = { x : 2 }
>> var a = { y : 0, x : 1, __proto__ : b }
>>
>> for (i in a){
>>     console.log(i + ": " + a[i]);
>>     delete(a.x)
>> }
>>
>> In this second example, a.x is deleted before it is visited. Thus,
>> following "If a property that has not yet been visited during
>> enumeration is deleted, then it will not be visited", it should not be
>> visited. The b.x property is no longer shadowed, but it was not supposed
>> to be enumerated in the first place. So can it be skipped?
>>
>> An alternative reading of the specification is that we are interested in
>> property /names/, not properties. Given this reading, in both examples a
>> property named 'x' was always reachable from a, so it must be enumerated
>> in both examples. Is this second reading closer to the intent of the
>> specification? I note that the current wording of the spec talks about
>> "properties" when things are being added and deleted, and "property
>> names" only when talking about duplicate enumerations.
>>
>> Thanks a lot!
>>
>> Gareth.
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>


More information about the es-discuss mailing list