Proposal: opt-out local scoping

Yuh-Ruey Chen maian330 at gmail.com
Thu Aug 28 10:36:31 PDT 2008


Dave Herman wrote:
> I think you're still going to have the same subtleties as hoisting with 
> this proposal, since all the variables assigned to in the block will be 
> in scope for the whole block; so they'll be `undefined' before being 
> assigned to and there will still be the same closure hazards where you 
> might think the variable was in scope in a nested block but in fact it 
> goes out to the nearest enclosing var { ... } block.

Actually, I forgot to mention that in there should no longer be any
hoisting in this case; it should be a syntax error:

blah = 10;
var {
    print(blah);
    blah = 20;
    print(blah);
}

The first |print(blah)| should be a syntax error. I think this is what
Python does too.

> > var {
> >     ...
> >     nonlocal x [ = y];
> >     ...
> > }
>
> For my tastes, this puts too much of a tax on referring to outer variables.

The alternative, which Pythonites have used for a while until the advent
of |nonlocal|, was to have an object/array in the outer scope and have
the outer variable be a property of that object:

var {
    function outer() {
        x = 10;
        a = [x];
        function inner() {
           return a[0];
        }
        return inner();
    }
}

However, this is pretty ugly and isn't very discoverable.

> These are the kinds of bugs that I think this semantics would result in: 
> when assignment implicitly binds variables, fat-fingering an assigned 
> variable name silently works and then causes unpredictable behavior 
> later. Whereas with traditional lexical scope, when you declare your 
> variables up front, both assignments and references are checked against 
> the variables in scope, and you get an immediate error -- even 
> statically detectable.

While this is true, this is far less of a problem than opt-in local
scoping, because the errors with opt-out local scoping are always going
to be local to the block/function the variable was assigned in.

Because of this, I believe the convenience is worth the cost.

> I don't believe that
>
>      var {
>          ...
>          a = f()
>          ...
>          b = g()
>          ...
>          c = h()
>          ...
>      }
>
> is that much less of a hardship than
>
>      {
>          ...
>          var a = f()
>          ...
>          var b = g()
>          ...
>          var c = h()
>          ...
>      }
>
> and I believe the benefits of a clearer semantics -- and clearer and 
> earlier errors on assignment to free variables -- are worth it. But I 
> agree that we need to do something to correct the semantics of looking 
> up free variables dynamically.

I don't particularly like |var { ... }| myself, but it's the only other
way besides a pragma - I would much prefer a pragma, which would pretty
much eliminate the usage of |var|.

> > And finally, it would be nice to have a pragma that can do this for us
> > (again, I don't recall the argument against them). Something like:
> > 
> >     use scope var;
> >     use scope let;
> >     use scope nonlocal; // default for backwards compatibility
>
> Lexical scope is in the air.  :)  Please take a look at the lexical 
> scope proposal on the wiki and offer any comments or suggestions:
>
>      http://wiki.ecmascript.org/doku.php?id=strawman:lexical_scope
>
> Essentially, the above is a less radical proposal that simply uses the 
> lexical scope that's already there in JavaScript, but as you suggest 
> enforces it with a pragma. The result is a language where free 
> variables, both in assignments and references, are a statically 
> detectable error, but with otherwise essentially the same semantics that 
> JavaScript already has.
>
> Dave
>   

I've taken a look at that, and while it does address free variables, I'd
still rather not have to sprinkle redundant |var|s everywhere.


More information about the Es-discuss mailing list