Generator issue: exceptions while initializing arguments

Brendan Eich brendan at mozilla.org
Sat Sep 8 18:21:34 PDT 2012


Allen Wirfs-Brock wrote:
> On Sep 8, 2012, at 5:20 PM, Brendan Eich wrote:
>> The contract of dataSnapshot wants a deep copy of aCollection, so it must make one. Fortunately if we bind parameters before the implicit yield, it can:
>>
>> function dataSnapshot(aCollection) {
>>   var snapshot = aCollection.clone();
>>   return (function* () {
>>     for (let i = 0; i<  snapshot.length; i++)
>>       yield snapshot[i];
>>   })();
>> }
>>
>> There's no need to add more magic to generators. Just use a function and a generator together. Compositionality.
>
> Yes, that does it.  But it's a pattern will will have to learn or discover. It may be obvious if you are thinking functionally but, it may be less obvious if you are thinking in terms of objects and method.

The same situation arises with closures, no generators needed:

function dataSnapshot(aCollection) {
   var snapshot = aCollection.clone();
   let i = 0;
   return {
     next: function () {
       if (++i == snapshot.length)
         throw StopIteration;
       return snapshot[i];
     }
   };
}

Anyone trying to avoid the .clone() call would be dispapointed. Anyone trying to avoid the extra level of function nesting would be disappointed. There is irreducible complexity here


>    Particularly if you expect that methods that return generators (I just spec'ed a bunch of those this morning) will have their names prefixed with * when you declare them.

When you write "method" here, I think you mean something different from 
what most people who use "method" when writing JS mean. It's functions 
all the way down :-P.

>     (I may be starting to double that allowing concise method syntax for generator is a good idea).

Could be. Not a big deal, but I don't see this case as relevant. Perhaps 
you should fully define your meaning of "method".

>> No, this yield; is well-defined and must mean (yield void 0); -- it should not be reinterpreted just because it is first.
>
> The wiki proposal doesn't appear to say that.  That's why I thought the yield; form was available.

That's a gap in the wiki'ed page. As in Python, and in SpiderMonkey for 
almost six years, yield like return has an operation operand. Unlike 
return, and after Python 2.5, yield is an operator (low-precedence, at 
assignment level).

I'd better review your draft specs -- shoot me some copy? Thanks.

>> In this thread, you and I have agreed on simpler scope/hoisting/defaulting/initialisting a la ES1-5. I think on reflection that this argues for the implicit yield in a generator function going before anything with observable effects, including argument defaulting.
>
> I agree, once you start doing some of the initialization early it leads you to want to do more of it within the generator.  In practice, make parameter initialization occur late it means that the raw argument list needs to be capture as part of the creation of the generator instance.
Yes. This is where we already parted company with Python, over parameter 
default values being computed on entry to the function, not just 
assigned then ("bound" in Python's one of many uses of "bind") from 
values evaluated at the function definition site.

It seems strictly simply to have the implicit |yield;| first, and to do 
defaulting after.

Temporal dead zone would follow if parameters were let-like, but I don't 
believe they can be. They're var-like, for at least these reasons:

1. In non-strict functions (1JS for-evah! ;-) arguments[0] aliases x in 
funtion f(x) { arguments[i] = 42; return x; }. We do not want let 
bindings to be aliased!

2. In non-strict functions, function f(x) { var x; ... } is legal. But 
in ES6, function f() {let x; var x;} is not legal.

/be


More information about the es-discuss mailing list