Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Deleting properties while iterating over them?

30 views
Skip to first unread message

Nicholas Nethercote

unread,
May 18, 2012, 9:51:50 AM5/18/12
to JS Internals list
Hi,

The following code snippet iterates over the properties of an object,
and deletes some of them on the way.

----
o = {a:1, b:2, c:3, d:4, e:5, f:6};

function isEven(x) { return x % 2 == 0; }

print(JSON.stringify(o));

for (let p in o) {
if (isEven(o[p])) {
print(o[p]);
delete o[p];
}
}

print(JSON.stringify(o));
----

The output from Spidermonkey is as I'd hope/expect:

{"a":1,"b":2,"c":3,"d":4,"e":5,"f":6}
2
4
6
{"a":1,"c":3,"e":5}

Is this valid code? Does it depend on implementation-dependent
behaviour? https://developer.mozilla.org/en/JavaScript/Reference/Statements/for...in
says that "In general it is best not to add, modify or remove
properties from the object during iteration, other than the property
currently being visited" which implies that it's ok.

Clarification is welcome. Thanks!

Nick

Jeff Walden

unread,
May 18, 2012, 2:21:48 PM5/18/12
to
On 05/18/2012 06:51 AM, Nicholas Nethercote wrote:
> The output from Spidermonkey is as I'd hope/expect:
>
> {"a":1,"b":2,"c":3,"d":4,"e":5,"f":6}
> 2
> 4
> 6
> {"a":1,"c":3,"e":5}
>
> Is this valid code? Does it depend on implementation-dependent
> behaviour?

The order in which properties are enumerated is implementation-dependent. Thus the first and last outputs will have unspecified orderings. The intermediate numbers printed also have unspecified ordering for the same reason.

> which implies that it's ok.

"ok" in the sense of always printing a six-property object, then 2/4/6 in some order, then an object with 1/3/5 in some order, yes.

The big issue deletion raises is deleting a property that hasn't been enumerated yet. If you do, you're guaranteed by spec not to see the property. But what if it's readded? Then I think it can optionally show up, although I'm not certain of this offhand. Or what if your attempt to delete a property occurs after it's been visited? Then the deletion attempt is irrelevant to the enumeration. But since enumeration order is unspecified, you can't know your attempt to delete a property will occur before its enumeration, or after it. You'd need some sort of side data structure to record that information. For that reason, if I remember correctly, I wrote that sentence to say only what definitely worked -- touching exactly the current property -- and not go into the weeds about particular messy interactions that happened to have semi-defined semantics.

Jeff

Nicholas Nethercote

unread,
May 18, 2012, 11:59:04 PM5/18/12
to Jeff Walden, dev-tech-js-en...@lists.mozilla.org
On Sat, May 19, 2012 at 4:21 AM, Jeff Walden <jwald...@mit.edu> wrote:
>
> "ok" in the sense of always printing a six-property object, then 2/4/6 in some order, then an object with 1/3/5 in some order, yes.

I don't care about the order in the real code I'm dealing with, so it
sounds like I'm ok.

Thanks everyone!

Nick

Jason Orendorff

unread,
May 18, 2012, 3:48:05 PM5/18/12
to Nicholas Nethercote, JS Internals list
On 5/18/12 8:51 AM, Nicholas Nethercote wrote:
> for (let p in o) {
> if (isEven(o[p])) {
> print(o[p]);
> delete o[p];
> }
> }
> Is this valid code? Does it depend on implementation-dependent
> behaviour?
Well, for-in is underspecified in the current ECMAScript standard. Under
a common-sense English reading of the spec (and there's no other way to
read it, it's not precise language) it seems like this should work. Each
time through the loop, the spec says: "Let /P/ be the name of the next
property of /obj/ whose [[Enumerable]] attribute is *true*."

http://people.mozilla.org/~jorendorff/es5.1-final.html#sec-12.6.4

So I guess "the next property" should eventually hit all the properties
you haven't deleted yet, right? It's um... yeah. It's not hard to come
up with complicated questions about this. Basically what MDN says is
spot-on.

As Waldo said, the enumeration order is unspecified, but SM's
enumeration order, or objects like your 'o' anyway, is de facto what
everybody has to do, and it may become standard someday.

-j
0 new messages