Will `for (var a of null) {}` throw an error?

# Glen Huang (10 years ago)

Ideally it shouldn’t, because its twin for (var a in null) {} won’t.

But looking at step 8 in people.mozilla.org/~jorendorff/es6-draft.html#sec-runtime-semantics-forin-div-ofexpressionevaluation-abstract-operation, people.mozilla.org/~jorendorff/es6-draft.html#sec-runtime-semantics-forin-div-ofexpressionevaluation-abstract-operation, when passing null to GetIterator(), it will throw a type error when the result of step 2 CheckIterable(null), which is undefind, is called in step 3 in the algorithm for GetIterator().

Did I miss something or the current spec does throw an error?

# Gary Guo (10 years ago)

To me since IsCallable(undefined) is false, so it throws an TypeError. Traceur and V8 will both throw a TypeError saying that cannot read property @@iterator from undefined or null, and Firefox throws a TypeError saying that null have no property. So it should be an error.

# Glen Huang (10 years ago)

In that case we have a gotcha.

Is there any interest to change that behavior? Since es6 isn’t finial yet.

# Domenic Denicola (10 years ago)

for in and for of do completely different things and there is no reason to expect consistency between them.

This was discussed already; search esdiscuss.org.

# Glen Huang (10 years ago)

Thanks. Found that discussion, and after thinking about it again, throwing errors on null/undefined actually makes sense, because it’s impossible to sliently loop over null/undefined with regular for loop (if you check length directly) or forEach directly. So throwing an error is actually consistent with how things work in es3/5.

# Gary Guo (10 years ago)

Actually I propose a change in texts in the specification.

CheckIterable ( obj )>1. If obj is undefined or null, then return undefined.>2. If type(obj) is Object, then return Get(obj, @@iterator).>3. Let box be ToObject(obj).>4. ReturnIfAbrupt(box).>5. Return the result of calling the [[Get]] internal method of box passing @@iterator and obj as the arguments.

This is way more too complex. We know that there are three situation:1. obj is undefined or null2. obj is of a primitive type3. obj is an object In 1, we don't care if it returns undefined or throw a TypeError. In ES6 spec, there are two uses of the undefined returned. One of them passes it as F to Call, the other passes it to ToObject. Both of them will result in TypeError. So we can just let this step throw TypeError instead of return undefined. I suggest we can a little bit combine these steps:

CheckIterable (obj)>1. Let box be ToObject(obj).>2. ReturnIfAbrupt(box).>3. Return the result of calling the [[Get]] internal method of box passing @@iterator and obj as the arguments.

If obj is undefined or null, the first step will fail and throw TypeError. If obj is primitive, it's boxed. If obj is an object, it is no-op in ToObject.

# Brendan Eich (10 years ago)

Your suggestion breaks Array.from and TypedArrayFrom.

# Gary Guo (10 years ago)

Date: Mon, 22 Dec 2014 21:28:54 -0800 From: brendan at mozilla.org

Your suggestion breaks Array.from and TypedArrayFrom.

In the spec:

  1. Let arrayLike be ToObject(items).

A type error will also be thrown since null and undefined are not ObjectCoercible.

# Brendan Eich (10 years ago)

Oops, you're right in these cases. The CheckIterable spec helper seems over-general. Allen?

# Allen Wirfs-Brock (10 years ago)

actually, in my working copy of the spec, CheckIterable has already been updated to look like:

1.	If obj is undefined or null, then return undefined.
2.	Return GetV(obj, @@iterator).

where GetV is similar to Get but it boxes non-object values before doing the property lookup

When you find issues like this, the best thing to do is to simply submit a bug ticket at: bugs.emcascript.org