lexical for-in/for-of loose end

Herby Vojčík herby at mailbox.sk
Mon Feb 6 12:03:57 PST 2012


Brendan Eich wrote:
> Grant Husbands wrote:
>>> But this is all beyond the spec.
>>
>> I don't think it is. What Herby's idea and these formulations present
>> is a way for let-based loops to have modifications in closures
>> captured in the for-head that alter the loop variables in a way that's
>> visible to the current loop iteration.
>
> And read back changes from the current iteration.
>
> Yes, I see that a new (novel!) observable semantic model is being
> proposed here, not an optimization. At first it seemed Herby was
> proposing just the usual optimizations.

Well, I hope I was understood. Even if not and something interesting 
sprang out, it's ok. I'll go into details later.

> I still do not think it's wise to specify in terms of such
> pointer-updating reference semantics, not for the body closures that
> want to capture loop control variables. But only if closures in the
> for-head capture loop variables? That would be Allen's "DWIM" (Do What I
> mean) semantics.
>
> DWIM is tempting. Perl is full of it and it can be convenient at first.
> It often blows back, badly, due to ambiguity.
>
>> As such, choosing whether or
>> not to use these formulations affects the spec.
>
> Agreed, with caution about bending the body closure model around this
> prematurely. If we pull it off, probably the body closures can do the
> same "optimization" -- but it's not clear we can pull it off.

Well, in fact what I proposed was not changing the behaviour of 
head-closures, but body-closures. Basically, the idea was: let the loop 
run in legacy semantics (only one block for the whole for-loop). All 
closures (head ones and body ones) access the same let-var and modify it.
But, for at the end of each iteration, if body-closures were created, 
rebind that closures to copy (or, better, child) of actual execution 
record with let-var being local (de-facto simulating per-iteration 
binding, but lazily; and only for async closures).

Spec-wise, I think it only needs to define two things, 
CopyExecutionRecord, which Grant already mentioned, or something similar 
like CopyWithFixedVars(ExecutionRecord, vars-to-fix) and 
ReplaceExecutionRecordBinding to allow closure(s) bound to original 
execution record re-bind it to its copy created by the former.

It's all. It solves this concern of Allen:
> In the case where there are no closure captures in the body we
> probably all expect implementations to actually share a single set of
> bindings across all iterations. If an implementation did that for
> this case it would yield the result the programmer to expecting.  But
> if an implementation actually did that in this case it would be an
> invalid optimization because of the proposed bind to only first
> iteration semantics.

With what I proposed, there is no 0th / 1st iteration semantics etc. 
since all the loop shares the binding through its whole run.

> ...
>
> Any preference for 0th over 1st iteration scope for closures in INIT
> binding initializer expressions?
>
> ...
>
> INIT may want the DWIM semantics, but TEST and NEXT before it for 2nd
> through Nth iterations really are more like parts of the BODY. Why
> should they form closures that magically reference "current iteration
> scope" when called later?

I definitely think INIT should not have any "special" behaviour for 1st 
and for subsequent iterations. The semantics of the loop is then much 
more straightforward and less magical. So in case of these desugaring, I 
am for 0th iteration. To be able to read loop as { INIT; for 
(;TEST;NEXT) BODY }.

> DWIM always falls to ambiguity. What did you mean? I dunno, just do it! :-P
>
> /be

Herby


More information about the es-discuss mailing list