Unresolved 3.1 issue: statements and substatements

# Allen Wirfs-Brock (17 years ago)

The ES3 specification has a single grammar production Statement that specifies what can occur in nested statement contexts such as if statement then and else clauses. This allows for some strange looking but valid code such as:

If (foo) var bar = "baz"; else var bar = "bam";

for (var i=0; i<10) var i=i++;

switch (i) { case 0 : var s = "one"; break; case 1: var s = "two"; break; default: var s = "other"; }

ES3.1 drafts have split statement into separate Statement and SubStatement productions. SubStatement excludes VariableStatment (and for a while, when we had them, function and const statements) and is used in most nested contexts such as the above. In the revised grammar, nested Statement productions only occur as the body of blocks and as function bodies. The motivation for this split was twofold. The primary reason was in support of blocks introducing nested lexical declaration environments. There was discussion regarding whether or not such nested declarations without explicit block braces should be considered to be in an implicit lexical block. In particular, some of us didn't want to further propagate to const and let the var-like possibility of multiple declarations within a lexical block of the same entity. For example, the thinking was that:

If (foo) const bar = "baz"; else const bar = "bam

should either be illegal or useless (each const would be in a separate implicit lexical block and would disappear immediately at completion of the block). The "illegal" possibility was preferred and SubStatement was created as a way to specify that.

The second motivation of the split was a hygienic objection to the occurrence of var (or any new declarations) in such positions. The belief was that most users who might code such things probably don't understand the actual semantics involved and may or may not get the result they expected. If this is the case, it is probably better to forbid it.

The exclusion of var from SubStatement is a breaking change to ES3. Some potentially existing valid ES3 programs that used var in these sorts of nested scenarios would not be valid ES3.1 programs. However, at the time, the combination of the two motivations seemed to carry enough weight to justify the change.

However, we have not included lexical blocks or any new lexical declarations in 3.1 and while we will eventually have them it seems unlikely that var will ever have block local scope. So the first argument doesn't really apply in the context of 3.1. The hygiene based argument is of the sort that we have generally only applied to strict mode restrictions. Strict mode is opt-in so minor breaking changes can be tolerated in strict code.

Recommendation #1: For non-strict mode code, ES3's support of VariableStatement in nested contexts remains in place. The above code examples remain valid non-strict ES3.1 code. However, ES3.1 strict mode will disallow such usage of VariableStatement. Whether this is accomplished via some variant of the current draft's Statement/SubStatement grammar or via prose restrictions for strict mode is a specification detail that can be resolved after we make this decision.

Assuming we follow that recommendation (or if we don't and continue to apply the restriction to all code) there is still another open question about the strict mode semantics. It is, can a VariableStatement occur as the Statement of a LabelledStatement. For example, the following is currently allowed in ES3:

IntegerVariables: var i,j,k,l,m,n; StringVariables: var A$,B$, C$;

Odd, but valid in ES3. More generally, ES3 allows any statement to have a label including all non-compound statements that can't possibly contain a break or continue.

Strict mode could restrict such usages and this is probably a good idea if you believe that one of the purposes of strict mode is to enable early flagging of code whose meaning is likely not to be what a programmer intended.

My opinion (but not a recommendation) is that we should probably just leave LabelledStatment alone for ES3.1, even in strict mode. However, we certainly could specify some strict mode restrictions for it if there is a consensus that they are desirable. So:

Feedback Request: Should we restrict usage of LabelledStatment in strict mode or leave it as specified in ES3.

# Maciej Stachowiak (17 years ago)

I agree with reverting the breaking change to non-strict mode. In
general I think it is unacceptable to make any incompatible changes to
standard mode without careful review of implementations and some study
of existing Web content to ensure they are safe.

I'm not sure what the benefit is of making the change in strict mode
only. It would be nice if ECMAScript were a block-scoped language, but
it isn't, and I am not sure disallowing var as an if or switch clause
is particularly helpful, especially when it is still allowed inside a
block serving in such a clause.

I also agree that labels should be left alone. They are not a very
commonly used feature and not especially a programming hazard, so they
do not seem worth a special strict mode rule.

# Waldemar Horwat (17 years ago)

As you noted, we can't break existing usages of var:

if (foo) var x = 3;

As such, var statements should be considered to be substatements and allowed anywhere. The declaration scope syntax rules would only apply to const and function declarations (and, in the future, let).

I don't see any benefit of getting strict mode involved with this -- the syntax ought to be the same with or without strict mode. var's are already hoisted, so the question of which block they're in is moot.

Waldemar