« Definite assignment | Main | Mascara 1.7 released »
Saturday
Nov272010

Another improvement related to 'var'.

Wrote yesterday about the new warning if a local variable is used before it is declared with 'var'. A related issue is var-declarations inside nested blocks. Say:

    
    if (2+2=5) {
      switch (true) {
        case false:
            var location;
      }
    }
    location = "something"

Here the var-statement does occur before the first reference to the variable, but the var-statement is nested inside if- and switch-blocks, which makes it easy to miss, and it is counter-intuitive that a deeply nested statement will change the meaning of a variable in an outer block. Furthermore, the statement cannot possibly ever be executed as the code looks now - but the var still have effect.

All this is highly counter-intuitive, and makes it unnecessary tricky to read code. Therefore Mascara provides a simple fix.

The new rule is: A local variable can only be accessed in the same block, or in nested blocks inside the block where the variable is declared with var.

E.g. this is legal:

    var location = "hello";
    location = "goodbuy";

And this is legal:

    var location = "hello";
    if (something) {
        location = "goodbuy";
    }

And this is legal:

    if (something) {
        var location = "hello";
        location = "goodbuy";
    }

But this is not legal, because the variable is used outside the block with the var-statement:

    if (something) {
        var location = "hello";    
    }
    location = "goodbuy";  //WARNING!

The last example will generate a ´Name not found: 'location' in function scope´-warning.

This is a small fix, but it is the accumulation of small things like these which makes the difference between long nights of bug-tracing, enjoyable development of new features.

Clarification: this does not change the run-time semantics of the var statement, it is just a compile-time verification which avoids some confusing and potentially buggy patterns. It is therefore not equivalent to the proposed 'let'-scopes which does change the semantics, e.g. by allowing you to 'shadow' variables declared in an outer scope.

PrintView Printer Friendly Version

EmailEmail Article to Friend

Reader Comments (4)

Are you saying that your last example is illegal ECMAScript code (or illegal in strict mode)? I've done if (!something) {var something = ...;} quite a few times and I thought that was perfectly legal.

November 27, 2010 | Unregistered CommenterEli Grey

Basically you've changed `var` to be `let`, at the cost of (probably?) an additional anonymous function for any block scope (including the additional cost of calling the function and having an extra context in your scope chain) and screwing up the most basic knowledge for any decent js developer. Sounds like a good job.

November 28, 2010 | Unregistered CommenterPeter van der Zee

@Eli: No, it is valid ECMAScript 5 code, even in strict mode. But the Mascara compiler will give a warning.

November 28, 2010 | Registered CommenterOlav

@Peter: No, the compiler does not create any additional anonymous functions. It is simply a compile-time warning which will prevent some bugs.

'Let'-scopes could be implemented as you suggest basically by creating an anonymous function for the block. But it is somewhat more tricky than just creating an anonymous function, since 'return', 'break' and 'continue' could occur inside the let-scope.

November 28, 2010 | Registered CommenterOlav
Comments for this entry have been disabled. Additional comments may not be added to this entry at this time.