issue: function hoisting and parameter default value initialization

Allen Wirfs-Brock allen at
Mon Oct 8 09:24:47 PDT 2012

On Oct 8, 2012, at 8:29 AM, Andreas Rossberg wrote:

> On 6 October 2012 02:35, Allen Wirfs-Brock <allen at> wrote:
>> Bottom line,
>>  I suggest we implement proposal 3, rather than the temporary conclusions
>> that were discussed at the Sept. meeting.
> Of the options you suggest, I also think that #3 is preferable.
> However, your examples have reconfirmed my suspicion that having
> defaults live within the scope of local declarations is the path to
> insanity. I suggest that we reconsider. There should be a clean,
> simple, and sane nesting of scopes here.

You desugaring would break ES<=5.1 compatibility for:

(unction (p) {
   var p;
   return typeof p

ES5.1 returns "string", your desugaring returns "undefined"

I'm actually favorably included  towards the intent of your proposal: parameter default value expressions can't reference bindings introduced in the body.  However, it needs to be specified in a way that preserves ES5.1 semantics.  I also think that, for new parameter constructs, that names defined in the parameter list should not be allowed to be the same as a function top-level declaration.  EG,

We have to allow this:

function f(p) {
    var p;

but we don't have to allow:

function f( ...p) {
   var p;

So, my alternative proposal #4 is:

       a) ES<=5.1 style formal parameters lists introduce var bindings and follow ES5.1 initialization rules. This permits top level inner functinon and var declarations that use the same name as a parameter.
       b) parameter lists containing any new ES6 syntax introduce let bindings for the parameters.  This prohibits multiple declaration of a formal parameter name and inner var/function redeclaration of a parameter name.
       c) parameter default value expressions do not have visibility of bindings created within the function body.


> Let me try again. How about the following desugaring?
>  function f(x1 = e1, ~~~, xN = eN) { body }
> means
>  function f(x1, ~~~, xN) {
>    if (x1 === undefined) x1 = e1;
>    ~~~
>    if (xN === undefined) xN = eN;
>    return (function(x1, ~~~, xN) { body })(x1, ~~~, xN);
>  }
> That is:
>  * no local declaration is visible in any of the defaults
>  * defaults can see other parameters, but they are initialized left to right
>  * local declarations behave as always, no extra rules needed
> There is an additional advantage to this scheme: to understand the
> definition of a default a caller never needs to look at the
> implementation details of f's body -- which I think is a very useful
> property. In particular, if a default expression is itself a function,
> and closes over one of the other arguments, then you actually get what
> you'd expect even if f, way down in its body, messes with some of
> those arguments (e.g. abusing them as a loop variable):
>  function f(i, log = (s) => print("f(" + i + "): " + msg)) {
>    log("starting...");
>    while (i > 0) {
>      log("processing " + i);
>      // ... whatever
>      --i;
>    }
>    log("done...");
>  }
>  f(6);  // no surprises here
> /Andreas

More information about the es-discuss mailing list