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