lexical for-in/for-of loose end

Grant Husbands esdiscuss at grant.x43.net
Sat Feb 4 18:36:03 PST 2012


Brendan Eich wrote:
> I agree we want to capture the first-iteration bindings in any closures in
> those declarators' initializers.
>
> This requires unrolling the loop once. Let's see how the desugaring from:
[snip]

For what it's worth, I agree with Mark's (2008) and Brendan's
desugarings and hereby withdraw my own, as the value-copying covers
barely any more use cases. Without some extensive feature like
let-aliasing, as Herby suggested, those solutions as good as we're
going to get, though I could have missed some of the discussion so
far.

By the way, if apparent code duplication in Brendan's desugaring is an
issue, a small change will fix that, with little cost, like so:
$loopEnd: {
  let $initdone = false;
  const $loop = { |d1, ... dN|
    if (!$initdone) {
      $initdone = true;
      d1 = e1, ... dN = eN;
    }
    if (!cond) break $loopEnd;
    body;
    update;
    $loop(d1, ... dN);
  }
  $loop()
}

As for modifications done by the for-head's closures, I have no strong
opinions. In both proposed desugarings, those modifications would be
invisible to the loop body fairly quickly. And in all proposals that
don't involve some kind of extensive variable aliasing, the for-head's
closures cannot observe values set in the loop body (beyond the first
iteration).

However, I hope I don't delay consensus by raising the possibility of
another desugaring using consts:

$loopEnd: {
  const d1 = e1, ... dN = eN;
  const $loop = { |d1, ... dN|
    if (!cond) break $loopEnd;
    body;
    update;
    $loop(d1, ... dN);
  }
  $loop(d1, ... dN);
}

That way, the for-head's closures can't easily have hidden unexpected
effects, though they'll still observe incorrect iterated values, and
it's less of a sledgehammer than disallowing capture altogether.

It's late, so I apologise if I've missed something really obvious or
typed garbage.

Regards,
Grant.


More information about the es-discuss mailing list