On Dec 27, 2012, at 1:51 AM, Andreas Rossberg <rossb...@google.com> wrote:

> I think hoisting can mean different things, which kind of makes this debate a 
> bit confused.

Yep. Sometimes people mean "the scope extends to a region before the syntactic 
position where the declaration appears," sometimes they mean "the scope extends 
to the function body," and sometimes they mean "function declaration bindings 
are dynamically initialized before the containing function body or script 
begins executing."

> There is var-style hoisting. Contrary to what Rick said, I don't think 
> anybody can seriously defend that as an "excellent" feature. First, because 
> it hoists over binders, but also second, because it allows access to an 
> uninitialized variable without causing an error (and this being bad is where 
> Dave seems to disagree).

Are you implying that my arguments are not serious? :-(

> Then there is the other kind of "hoisting" that merely defines what the 
> lexical scope of a declaration is. The reason we need this backwards-extended 
> scope is because we do not have an explicit let-rec or something similar that 
> would allow expressing mutual recursion otherwise -- as you mention. But it 
> does by no means imply that the uninitialized binding has to be (or should 
> be) accessible.

No, it doesn't. I'm not interested in arguments about the "one true way" of 
programming languages. I think both designs are perfectly defensible. All 
things being equal, I'd prefer to have my bugs caught for me. But in some 
design contexts, you might not want to incur the dynamic cost of the 
read(/write) barriers -- for example, a Scheme implementation might not be 
willing/able to perform the same kinds of optimizations that JS engines do. In 
our context, I think the feedback we're getting is that the cost is either 
negligible or optimizable, so hopefully that isn't an issue.

But the other issue, which I worry you dismiss too casually, is that of 
precedent in the language you're evolving. We aren't designing ES1 in 1995, 
we're designing ES6 in 2012 (soon to be 2013, yikes!). People use the features 
they have available to them. Even if the vast majority of 
read-before-initialization cases are bugs, if there are some cases where people 
actually have functioning programs or idioms that will cease to work, they'll 
turn on `let`.

So here's one example: variable declarations at the bottom. I certainly don't 
use it, but do others use it? I don't know.

>> - It automatically makes forward references work, so you can:
>> * order your definitions however it best "tells the story of your code," 
>> rather than being forced to topologically sort them by scope dependency
>> * use (mutual) recursion
> 
> Right, but that is perfectly well supported, and more safely so, with TDZ.

My point here was just about hoisting (perhaps a bit OT, but the question came 
up whether hoisting is bad) -- specifically, of having declarations bind 
variables in a scope that extends to a surrounding region that can cover 
expressions that occur syntactically earlier than the declaration itself. TDZ 
is orthogonal.

>> - It binds variables without any rightward drift, unlike functional 
>> programming languages.
> 
> I totally don't get that point. Why would a rightward drift be inherent to 
> declarations in "functional programming languages" (which ones, anyway?).

Scheme:

    (let ([sq (* x x)])
      (printf "sq: ~a~n" sq)
      (let ([y (/ sq 2)])
        (printf "y: ~a~n" y)))

ML:

    let sq = x * x in
      print ("sq: " ^ (toString sq) ^ "\n");
      let y = sq / 2 in
        print ("y: " ^ (toString y) ^ "\n")

ES6:

    let sq = x * x;
    console.log("sq: " + sq);
    let y = sq / 2;
    console.log("y: " + y);

Obviously functional programming languages can do similar things to what ES6 
does here; I'm not saying "functional programming sucks." You know me. :)

Dave

_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to