A couple of questions regarding let, hoisting and block scope

2011-03-21 Thread Claus Reinke

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, and from the no use before 
   declaration in [1], it seems that let bindings won't be hoisted,

   not even to their enclosing block.

   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) ..}
   }

   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).


   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() { }()) ).

   [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 ..
   }

   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@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: A couple of questions regarding let, hoisting and block scope

2011-03-21 Thread David Herman
   Hoisting isn't nice in general, and from the no use beforedeclaration 
 in [1], it seems that let bindings won't be hoisted,
   not even to their enclosing block.

That page is not yet complete. There's plenty more work to do on it, but we 
probably won't be able to find much time to do that work till after May, I'm 
afraid.

   But hoisting is also the basis for making mutually recursive
   function definitions work without pain. Will we have todeclare all 
 function names of recursive function groupsahead of defining them (with a 
 top-down parser, there'd
   be many more than just two function names to list)?

Function declarations (whether via |function foo(...) { ... }| or |const 
#foo(...) { ... }|) will almost certainly be hoisted.

   {let odd, even; // needed?
   odd = function (n) { .. even(n-1) ..}
   even = function (n) { .. odd(n-1) ..}
   }

Pre-declaring odd and even would be needed for this form, yes. (If someone 
wants to change JS to have Python/CoffeeScript-like implicit variable scope, 
they'll have to get past my dead body first.) But for function definitions, 
you're better off using function declarations rather than assignment.

   or, with #functions [2]
 
   {const odd, even; // needed?
   const #odd (n) { .. even(n-1) ..}
   const #even (n) { .. odd(n-1) ..}
   }

As I say, since these are the declarative form, you get hoisting and don't need 
to pre-declare them.

Working out the details of the scoping semantics is really subtle, though. When 
you have hoisting of functions, the spec has to cope with situations like:

{
let x;
{
foo();
let x;
function foo() { ... x ... }
}
}

There are a bunch of careful details we have to work through, but we haven't 
gotten to it yet.

This really isn't a good time or venue to discuss the details. The spec isn't 
complete or ready for review, and es-discuss is not the place to do that work.

   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() { }()) ).

Ugh. Just... no.

Dave

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