barrier dimension, default dimension

Brendan Eich brendan at mozilla.com
Fri Dec 28 13:32:45 PST 2012


David Herman wrote:
> On Dec 28, 2012, at 12:11 PM, Brendan Eich<brendan at mozilla.com>  wrote:
>
>> David Herman wrote:
>>> Andreas, can you explain why you dismiss TDZ-RBA-UNDEF as a viable option? The bug that motivates all the arguments you've made is read-before-initialization, not write-before-initialization.
>>>
>> Since you mailed the list I will jump in before Andreas answers. TC39 considered TDZ-RBA-UNDEF in several July meetings in adjacent years.
>
> Heh, thanks for providing historical context. I think there are some flaws in the reasoning from those past meetings. I'll reply to some points from the cited minutes inline:
>
>> --- begin quote ---
>>
>> But if we try to treat let like var, then let and const diverge.
>
> I don't think there's some divergence that's okay, but they actually don't have to diverge that much.

The argument (one of them) is about how much: UBI vs. RBA-UNDEF. 'const' 
must have UBI an error. We had consensus in July 2011 (re-checked in 
July 2012 if my memory serves) that 'let' and 'const' should both be 
subject to the same rule, modulo 'let x;' implicitly initializing with 
undefined.

We could diverge let as you propose, via RBA-UNDEF, but that is a 
greater divergence than we had in the previous consensus or quasi-consensus.

>> We cannot treat const like var and allow any assignment as "initialization", and we must forbid assignments to const bindings -- only the mandatory initializer in the declaration can initialize. Trying to allow the "first assignment to a hoisted const" to win quickly leads to two or more values for a single const binding:
>>
>> {
>>    x = 12;
>>    if (y) return x;
>>    const x = 3;
>>    ...
>> }
>
> This is of course a silly semantics, but I argue that const should have a syntactic restriction that it can only be assigned to in its initializer -- the above should be a syntax error. Once you have that restriction, there's no observable difference between the read barrier and the read-write barrier.

Yup.

>> The situation with let is constrained even ignoring const. Suppose we treat let like var, but hoisted to block top instead of body/program top, with use before set reading undefined, or in an alternative model that differs from var per temporal dead zone, throwing. So:
>>
>> {
>>    print(x);
>>    x = 12;
>>    let x;
>> }
>>
>> would result in either print being called with undefined or an error on the use of x before it was set by the assignment expression-statement -- those are the two choices given hoisting.
>>
>> But then:
>>
>> {
>>    x = 12;
>>    print(x);
>>    let x;
>> }
>>
>> would result in either 12 being printed or an error being thrown assigning to x before its declaration was evaluated.
>>
>> Any mixture of error with non-error (printing undefined or 12) is inconsistent.
>
> This is just bogus reasoning. What consistency could we be talking about?

That both of the above should be errors to be "more consistent" in 
handling likely-buggy inputs. This was implicit, you're right, but I 
recall Sam at the whiteboard writing some of these, and the group assenting.

I'm not recounting to say we are bound by whatever happened then, rather 
trying to recollect exactly what consistency was being talked about there.

>> One could defend throwing in the use-before-assignment case, but it's odd.
>
> What's odd about throwing in use before assignment?

I'm trying to remember. First, that "use-before-assignment case" must 
have been the x in print(x) here:

{
   print(x);
   x = 12;
   let x;
}

I remember Sam permuting the statements to get the second case, which 
under RBA-UNDEF would not throw, and that may be what seemed "odd".

The group as a whole seemed to want errors for both of these examples. 
That maximizes a kind of error-catching-over-unusual-order consistency.

>> And throwing in both cases is the earlier consensus semantics of temporal dead zone with a distinct state for lack of initialization (even if the initialization is implicit, e.g., in a declaration such as let x; being evaluated). Here "initialization" is distinguished from assignment expressions targeting the binding.
>
> This is just circular: "this should be the semantics because we agreed it should be the semantics."

This was just an observation that throwing in both examples is the 
earlier consensus semantics for TDZ and 'let'.

>> Trying to be like var, printing undefined or 12, is possible but future-hostile to guards and gratuitously different from const:
>>
>> {
>>    x = 12;
>>    const G = ...;
>>    let x ::G = "hi";
>> }
>
> This where I think we really made a mistake. There's nothing preventing us from having additional restrictions for guarded declarations -- cross the bridge when we come to it.

Sure, and I agree, but if you delete guards the arguments for maximal 
error-catching consistency and refactoring from let to const (more 
below) still stand.

>> We want to be future-proof for guards, and even more important: we want to support *refactoring from let to const*. Ergo, only temporal dead zone with its barriers is tenable.
>
> I disagree. If you refactor from let to const it's because you only want a single assignment. It's nonsensical to refactor:
>
>      {
>          let x;
>          x = 1;
>          x = 2;
>      }
>
> to:
>
>      {
>          const x;
>          x = 1;
>          x = 2;
>      }
>
> That should just be a syntax error. Const has more restrictions. You have to play by its rules.

That's not the refactoring to consider. The hard case for refactoring 
from TDZ-RBA-UNDEF 'let' to any 'const' we can agree on is this:

{
   ...
   let x;
   ...
   x = computed();
   ...
}

refactored to

{
   ...
   const x = computed();
   ...
}

The three meta-ellipses in the 'let' version may interact with effects 
in computed(), so refactoring to the two ...s in the 'const' version is 
not always easy. The "refactoring from let to const" argument is about 
not allowing any such case with 'let' to crop up. That's all.

This may seem like small beans but it's a design choice that, all else 
equal, avoids a problem. Recall Crock on arguments about "oh, that's not 
a problem (much)...". Such little problems are still problems. Why not 
design this one out of ES6?

> So I disagree with that whole line of reasoning.

Curious how you feel after my reply here.

>   But I'd like to hear Andreas's reasoning why he feels there should be a write barrier.

Me too -- cc'ing him in case he's not keeping up with es-discuss.

/be


More information about the es-discuss mailing list