On Sep 8, 2012, at 5:20 PM, Brendan Eich wrote:

> Allen Wirfs-Brock wrote:
>> On Sep 8, 2012, at 3:59 PM, Brendan Eich wrote:
>> 
>>> Here's an attempt at a crucial experiment:
>>> 
>>> js>  var g = 'now'
>>> js>  function f(a = g) { yield a; }
>>> js>  var it = f()
>>> js>  g = 'later'
>>> "later"
>>> js>  it.next()
>>> "later"
>>> 
>>> So I'm wrong, SpiderMonkey inserts the impliciti |yield;| before parameter 
>>> defaulting. Rats.
>>> 
>>> It may not matter, but I still think early beats late. That Python binds in 
>>> the definition context may still be relevant, even though Python evaluates 
>>> parameter default values at function definition evaluation time (way 
>>> early), insofar as translating the above to Python:
>>> 
>>> Python 2.6.6 (r266:84292, May 28 2011, 19:08:00)
>>> [GCC 4.2.1 (Apple Inc. build 5664)] on darwin
>>> Type "help", "copyright", "credits" or "license" for more information.
>>>>>> g = 'now'
>>>>>> def f(a = g):
>>> ...   yield a
>>> ...
>>>>>> it = f()
>>>>>> g = 'later'
>>>>>> it.next()
>>> 'now'
>>> 
>>> does indeed result in 'now'.
>> 
>> I think early beats late and that this concept extends to include any code 
>> within the generator function that is involved in setting up the initial 
>> state of the generator.
> 
> So far, so good, but I think the rest of your message mixes shared mutable 
> objects in the heap (a JS feature, not a bug) with generators and then tries 
> to patch generators to avoid the consequences of the shared-mutable-objects 
> feature.

sounds like real-life JS programming...

> 
>>    For example, it seems quite reasonable for somebody to try to write 
>> something like:
>> 
>> function *dataSnapshot(aCollection) {
>>    snapshot = aCollection.captureCurrentState();
> 
> (missing var or let -- implicit global...)
oops
> 
>>    //initialization complete
>>    for (let i=0; i<snapshot.length; i++) yield snapshot[i]
>>    throw StopIteration;
> 
> This last throw statement is unnecessary and no one should write it.

yes, I blurred over that when rereading the generator proposal

> 
>> }
>> ...
>> 
>> lets snappedItr= dataSnapshot(myData);
>> ...
>> ...
>> myData.doABunchOfUpdates();
> 
> 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 = aColllection.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.  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.   (I may 
be starting to double that allowing concise method syntax for generator is a 
good idea).


> 
>> ...
>> ...
>> for (let d of snappedItr)  {/* look at old data */}
>> ...
>> 
>> Unfortunately, they will see the new updated data not the old data when they 
>> iterate.
>> What they need is the ability to move the implicit "initialization is 
>> complete" yield from the beginning of the body  to the point of the comment 
>> I provided.  We don't have a way to do that and , of course, if we did it 
>> would complicate things and probably create other ways to mess things up.  
>> The only reason approach that I've come up would be to treat a yield without 
>> an associated expression as the initialization complete marker:
>> 
>> function *dataSnapshot(aCollection) {
>>    snapshot = aCollection.snapState();
>>    yield;
> 
> 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.

> 
> 
>>    //initialization complete
>>    for (let i=0; i<snapshot.length; i++) yield snapshot[i]
>>    throw StopIteration;
>> }
>> 
>> 
>> The semantics would probably be if the body does not contain such a yield, 
>> then one is auto generated at the top of the function body. So the default 
>> would be "late" (possibly include the arguments) but it could be explicitly 
>> make "early" to an arbitrary point in the body.
> 
> We still have the choice of the implicit yield going after argument 
> defaulting, not before. SpiderMonkey implements before, though, and my own 
> argument from compositionality, above, makes it more clear to me that we 
> should go with implicit-yield-first. This makes contrived throwing parameter 
> default expressions throw "late" but if that matters, use a function combined 
> with a generator.
> 
> 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.

Allen


_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to