Declarations

liorean liorean at gmail.com
Tue Apr 15 16:41:35 PDT 2008


> Michael O'Brien wrote:
>  > As a follow up, the following somewhat surprised me.
>  >
>  > {
>  >      let b = 1
>  >      {
>  >          function fun() {
>  >              print("CALL: " + b)
>  >          }
>  >      }
>  > }
>  > fun()
>  >
>  > gives:
>  >
>  > **ERROR** EvalError: uncaught exception: ReferenceError: unresolved
>  > lexical reference {multiname: [ns public '']::b [ns internal '']::b
>  > [ns public '__ES4__']::b } (near /Users/dherman/es4/src/builtins/
>  > Error.es:86:55-86.55)
>  >
>  >
>  > ie. the function is hoisted to the outer var block, but does not seem
>  > to capture the scope chain of where it was declared and b is out of
>  > scope.
>  >
>  > Is this correct or an RI bug?

On 16/04/2008, Waldemar Horwat <waldemar at google.com> wrote:
> This is incorrect and an RI bug, but for a different reason:  fun should be undefined in the outer scope, since it should not get hoisted out of the inner block, as we agreed at the last face-to-face meeting.

While ES3 has that case as a SyntaxError, implementations of ES3 allow
it. SpiderMonkey (tested in JS1.7 mode) is the only browser hosted
implementation that I could find which does not hoist the function
declaration and initialisation to the top of the current function
scope at compile time. What SpiderMonkey does is that it hoists the
function to the current function scope at run time though. Which means
that:

    alert(foo);
    {
        function foo(){}
        alert(foo);
    }

is a reference error at the first line, while:

    {
        function foo(){}
        alert(foo);
    }
    alert(foo);

is not an error.

So the choice to not hoist a function declaration to function scope at
least at run time seems like it would break code written for any of
our current browser hosted implementations. I would be much more
comfortable with hoisting the declaration at compile time and doing
the initialisation at run time to preserve the relation with control
flow. (As I discussed in [1].)

Isn't it better to do what SpiderMonkey does for regular function
declarations in statements, as a lowest-common-denominator for how
widely the function declaration is accessible, and only make a
qualified block scoped function:

    {
        let function(){}
    }

to be bound in block scope?



Also another point to make about this: You are effectively adding a
function-declaration-within-statement production, something ES3 left
undefined. Browser implementations vary in how these constructs are
treated with relation to control flow and compile time vs. run time
initialisation (see [2] for a breakdown of behaviour in various
engines). If you allow it at all, you should be explicit about what
the rules for declaration hoisting and initialisation timing really
are - current implementations are not interoperable.

I personally prefer preserving control flow versus preserving
use-before-definition mechanics (this is more useful of the two
absolutes, and doing something like the inconsistency of
JavaScriptCore is madness), and preserving the scoping to function
level since all browser hosted implementations currently guarantee use
even after the block has exited.


[1] <uri:https://mail.mozilla.org/pipermail/es4-discuss/2007-March/000483.html>
[2] <uri:https://mail.mozilla.org/pipermail/es4-discuss/2007-March/000495.html>
-- 
David "liorean" Andersson



More information about the Es4-discuss mailing list