A couple of questions regarding let, hoisting and block scope

Dmitry A. Soshnikov dmitry.soshnikov at gmail.com
Mon Mar 21 00:20:56 PDT 2011


On 21.03.2011 19:13, Claus Reinke wrote:
> I was looking forward to a Javascript with block scope at last,
> but on looking through the proposals, I have some questions:
>
> 1. hoisting vs recursive function definitions
>
>    Hoisting isn't nice in general,

It's just a technique. It has pros and cons (http://bit.ly/eg4Daz)

> and from the "no use before    declaration" in [1], it seems that let 
> bindings won't be hoisted,
>    not even to their enclosing block.
>

Why? It does hoisted (at least in the semantics of current SM1.8.5). In 
rough approximation, `let` is just a syntactic sugar for immediately 
invoked lambdas:

let (x = 10, y = 20) {
   /* code */
}

is just a:

(function (x, y) {
     /* code */
})(10, 20);

A similarly:

if (true) {
     console.log(x, y); // undefined, undefined
     let x = 10, y = 20;
     console.log(x, y); // 10, 20
}

is just a:

if (true) {
     (function () {
         console.log(x, y); // undefined, undefined
         var x = 10, y = 20;
         console.log(x, y); // 10, 20
     })();
}

That said, the approximation is rough (after all, things such as 
`break`, `continue`, etc. should be considered), but the basic idea is this.


>    But hoisting is also the basis for making mutually recursive
>    function definitions work without pain. Will we have to    declare 
> all function names of recursive function groups    ahead of defining 
> them (with a top-down parser, there'd
>    be many more than just two function names to list)?
>    {    let odd, even; // needed?
>    odd = function (n) { .. even(n-1) ..}
>    even = function (n) { .. odd(n-1) ..}
>    }
>

Nope, it seems ugly. If you want a function expression (FE), then use it 
as is:

let odd = #(n) {
   /* code */
};

Or, since function statements (FS) will be standardized, just:

function odd(n) {
   /* code */
}

>    or, with #functions [2]
>
>    {    const odd, even; // needed?
>    const #odd (n) { .. even(n-1) ..}
>    const #even (n) { .. odd(n-1) ..}
>    }
>
>    Once function definitions are constant, there doesn't seem
>    to be much harm in a limited form of hoisting: for a sequence
>    of constant function definitions, not interrupted by other    
> statements, implicitly introduce all function names defined    in the 
> sequence at the start of the sequence (to simplify    recursive 
> definitions).
>

Yes, definitions in loop is also one of the hoisting's reasons (though, 
it can be managed an in the system without hoisting).

>    The alternatives would be manual duplication of function    name 
> lists, or introducing a dedicated letrec syntax for    recursive 
> definitions (the latter might actually be preferable).
>
>    Am I missing something here, or hasn't this been discussed?
>    2. ease of transition
>
>    The general idea seems to be to introduce separate syntax,
>    to force programmers to "buy in" to the new semantics. This
>    should lead to a clean transition, but not an easy one.
>
>    The downside is that no-one can test the waters as long as    old 
> implementations (do not understand 'let') retain substantial    
> marketshare. This is sad because implementations could
>    start helping programmers right now (read: from the next
>    release), to prepare for the eventual transition.
>
>    One idea would be to start separating "strong" and "weak"
>    blocks, where weak blocks '{ }' are the standard, non-scoped
>    ones and strong blocks '{{ }}' (to steal no syntax) would be
>    block-scoped (for instance, map to "(function() { }())" ).
>

Not sure and don't think so. Also, it will complicate the picture in a 
whole. Two curly braces are enough for JS from C's syntax.

foo = ->
     # coffee

let foo = #() {{
    // js
}}

>    [we can't map '{{ }}' by translating 'var' to 'let': unless all
>     blocks involved are strong blocks, 'let' is more local]
>
>    Another idea would be to add a pragma: "no hoisting";
>    (or extend "use strict" to encompass this). Upon which
>    the implementation should warn or error on any code
>    that captures variable occurences by hoisting. For instance:
>
>    function F() {
>        "no hoisting";
>        .. x ..
>        if ( .. ) { var x; .. }
>        .. x ..
>    }
>

Also it seems as a complication for the language. Again, hoisting is 
just a technique, there is no need to complicate your code with 
additional pragmas (especially with that technically-jargon term 
"hoisting"). It's better to build your code accordingly and manually -- 
just put all definitions to the top yourself.

Dmitry.

>    should produce warnings (at least at the hoisted declaration,
>    probably also at the captured uses).
> Claus
>
> [1] http://wiki.ecmascript.org/doku.php?id=harmony:let
> [2] http://brendaneich.com/2011/01/harmony-of-my-dreams/
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss



More information about the es-discuss mailing list