Questions/issues regarding generators

Allen Wirfs-Brock allen at wirfs-brock.com
Fri Mar 15 23:34:53 PDT 2013


On Mar 15, 2013, at 5:55 PM, Waldemar Horwat wrote:

> On 03/14/2013 04:14 PM, Brendan Eich wrote:
>> Andreas Rossberg wrote:
>>> On 14 March 2013 23:38, Brendan Eich<brendan at mozilla.com>  wrote:
>>>> Andreas Rossberg wrote:
>>>>> That leaves my original proposal not to have generator application
>>>>> return an iterator, but only an iterable. Under that proposal, your
>>>>> example requires disambiguation by inserting the intended call(s) to
>>>>> .iterator in the right place(s).
>>>> That's horribly inconvenient. It takes Dmitry's example:
>>>> 
>>>>  function* enum(from, to) { for (let i = from; i<= to; ++i) yield i }
>>>> 
>>>>  let rangeAsGenerator = enum(1, 4)
>>>>  let dup = zip(rangeAsGenerator, rangeAsGenerator)  // Oops!
>>>> 
>>>> which contains a bug under the Harmony proposal, to this:
>>>> 
>>>>  function* enum(from, to) { for (let i = from; i<= to; ++i) yield i }
>>>> 
>>>>  let rangeAsGenerator = enum(1, 4)
>>>>  let dup = zip(rangeAsGenerator[@iterator](), rangeAsGenerator[@iterator]())
>>> 
>>> No, why? The zip function invokes the iterator method for you.
>> 
>> Sure, but only if you know that. I thought you were advocating explicit iterator calls.
>> 
>> A call expression cannot be assumed to return a result that can be consumed by some mutating protocol twice, in general. Why should generator functions be special?
>> 
>> I agree they could be special-cased, but doing so requires an extra allocation (the generator-iterable that's returned).
>> 
>> Meanwhile the Pythonic pattern is well-understood, works fine, and (contra Dmitry's speculation) does not depend on class-y OOP in Python.
>> 
>> I guess it's the season of extra allocations, but still: in general when I consume foo() via something that mutates its return value, I do not expect to be able to treat foo() as referentially transparent. Not in JS!
> 
> Does for-of accept only iterables, only iterators, or both?  Presumably a function like zip would make a similar decision.  The problem is if the answer is "both".

Strictly speaking for-of only accepts iterables since it always invokes the @@iterator on the value to the RHS of the 'of' keyword.  For-of expects to get a iterator back from the @@iterator call.

Using informal interface descriptions this can be described as:

interface <iterable> {
   @@iterator: ()-> <iterator>
}

interface <iterator> {
   next: () ->  <nextResult>
}

interface <nexdtResult> {
   done: <boolean>,
   value: <any>
}

class Array implements <iterable> {...}
class Map implements <iterable> {...}
class Uint32Array implements <iterable> {...}
etc.

class "builtinArrayIterator" implements < iterator >+< iterable > {...}
class "builtinMapIterator" implements < iterator >+< iterable > {...}

The dual nature of the built-in iterators is nice because it allows formulation like:

for (v of myArray) ...  //iterate over an array using its default iterator
for ([k,v] of myArray.entries())  ... //iterate over an array using an alternative iterator as the iterable
for (ev of (for (v of myArray) if (v&1==0) v)) ...  //the iterable is a generator expression

My understanding of Andrea's concerns is that there is a hazard that somebody might try to invoke @@iterator more than  once on an iterator that was also an iterable.  This isn't a hazard at all, in the context of for-of and the built-ins.  for-of never calls @@iterator more than once in that manner.  Multiple invocations of @@iterable is only possible using explicit user written calls. Also all the built-in iterable collections are specified  to return a new iterable instance for each call to @@iterable so there shouldn't be any concern about accidentally getting the same iterator back from any built-in collection.

If we are concerned about the hazard of users coding multiple @@iterator calls to a single built-in iterator instance, the simplest solution is probably to define @@iterator for them such that they throw if the iterator instance is not in its initial state.  User defined iterators are, of course, free to define @@iterator in any manner they wish.  They might "clone" the iterator, or throw or whatever they wanted. 

Allen







> 
>    Waldemar
> 
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
> 



More information about the es-discuss mailing list