Re: How to correctly spec sequences requiring an iterable

On Nov 15, 2013, at 8:24 AM, Jason Orendorff wrote:

> On Fri, Nov 15, 2013 at 10:08 AM, Boris Zbarsky <bzbarsky@mit.edu> wrote:
>> An obvious question that arises is what the definition of iterable is.
>> 
>> Is it something for which HasProperty(obj, @@iterator) returns true?
>> 
>> Is it something for which GetProperty(obj, @@iterator) returns something
>> other than undefined?
>> 
>> Is it something for which GetProperty(obj, @@iterator) returns a callable
>> object?
> 
> Array.from[1] has to make this determination, such that it can't "just
> iterate and see". At the moment it is spec'd to use HasProperty(obj,
> @@iterator). But that is inconsistent; other places where we check for
> a method always use the third criterion. I hope Allen can weigh in.
> 
> -j
> 
> [1] http://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.from
> 

I already have an abstract operation GetIterator(obj)  [1] to access an Iterator when an valid @@iterator must be present.  If you trace through the steps (and unfortunately, the definition of Invoke is missing in this draft) you will see that the checks it performs are:
        Throws if any of the following are true, Type(obj) is not Object, obj[@@iterator] is undefined, obj[@@iterator] is not callable, Type(obj[@@iterator]()) is not Object.

For consistency, I should probably define another abstract operation for use in the small number of places that conditionally check for an Iterable.

Currently, Array.from [2] does a HasProperty(@@iterator) check followed by a call to GetIterator.   In other words, the existence of an @@iterator property is all that is need to select the Iterator side of the union type.  But that is then followed by validation specified via GetIterator.  If the value of @@iterator doesn't validate you get a runtime exception rather than a fall back to the other side of the union type.

There is one detail of the above that I think should change.  Rather than doing HasProperty(@@iterator) to make the union type discrimination, it should do:
     6    Let iteratorGetter = Get(items, @@iterator).
     7.5 If iteratorGetter is undefined or null then let usingIterator be false; otherwise let usingIterator be true.

(I'll actually do a bit more refactoring, but in the context of [2] those are the essential changes)

This allows a subclass or individual object to disinherit support of an inherited @@iterator.

So, going back to Boris's original question, you should discriminate an object as an Iteratable  by this test:
    An object is an iterable if it has a @@iterator whose value is neither undefined or null.

An object that has an  @@interator property whose value (other than undefined or null) is not a function is still consider to be an Iterable, but it is malformed. Actually trying to retrieve its Iterator will produce a runtime error.

    
[1]: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-getiterator  
[2]: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.from steps 6-8

Received on Friday, 15 November 2013 17:29:27 UTC