On Jul 30, 2011, at 1:58 PM, Patrick Walton wrote:
> Currently, in Rust variables hoist, just as in JavaScript. I would like to
> propose removing this feature, and having each "let" introduce a new scope.
This matches C++, so that's a plus for anyone coming to Rust from the main
Mozilla "systems" language.
> Other, weaker but still compelling arguments in my mind:
>
> This code compiles but is awfully confusing:
>
> fn main() {
> x = 3;
> log_err x;
> let int x;
> }
FYI, and not bearing on Rust at all IMHO (so feel free to skip), we on Ecma
TC39 just renewed our agreement, with better joint understanding of the
rationale, for let and const (and function-in-braced-block) hoisting to start
of block *and* for use before initialization (the "temporal dead zone") to be
an error in JS.next (ES6).
JS already has function hoisting, which wins for programming in top-down style,
maintaining source without having to topologically sort functions, etc. I made
functions hoist to top of program or outer function body to mimic letrec, way
back in the day. Given this precedent, we believe
function-declaration-in-block, which binds a block-local (as let does), should
hoist to top of block and be initialized on entry to block.
Last fall, we tried to make let (and const) open C++-style implicit scope at
declaration site, till end of explicit block. But this does not work with
function hoisting:
const k = 0;
function outer(x, y) {
if (x) {
inner();
const k = y;
function inner() { print(k); }
inner();
}
}
outer(42);
The first inner() call cannot see k under the let* or C++-based scope rule. If
this inner call should print 0 then function inner has dynamic scope. If it
should throw an error then the scope rule is equivalent to hoisting k to top of
its containing block. Likewise for let.
The reason the dead zone in which use of k before it has been initialized is a
temporal or dynamic zone, not a lexical or static zone, is shown above: inner's
declaration is dominated by k's definition, so a lexical dead zone would allow
it. But then for this approach to differ from temporal dead zone, the first
call to inner either must get undefined from k (two values for one const), or
get the outer k (dynamic scope).
Hence hoisting for all binding forms, with a read and write barrier for use
before set (write barrier for let; const must be initialized in its declaration
and it's a static error to assign anywhere else). The barriers are potentially
significant performance penalties for upvars (any directly-in-block, not
in-nested-function, use cases are probably bugs; we're still arguing about
whether to make those static errors). We shall see.
If Rust hoists nothing, in particular Rust does not hoist nested fns, then it
does not face the same predicament.
/be
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev