Declarations
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 Tue, Apr 15, 2008 at 1:56 PM, Michael O'Brien <mob at mbedthis.com> 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?
RI bug.
Jon, thanks. Any thoughts on the original post?
This is an RI bug too (my fault). AS3 initializes programs in a single pass, before evaluating the top level code. The RI does both in one pass. I just filed a bug (bugs.ecmascript.org/ticket/382)
Jeff,
Can I tease out a bit more detail. I'm not sure I agree with what the
correct answer should be.
Lars raised the issue with "var" a while back and I think, if my
memory serves me, the conclusion
was that the variable should be hoisted to the top of the var block,
but the initialization statement
should execute in place.
ie.
=> declaration for y hoisted to here
print(y) // Y should exist here but be null x = 1 var y = x // Assigment from x remains here
If the above is true for variables, should we not have the same rules
for functions and for
classes? ie. shouldn't class static initialization code remain inline
where the class is defined?
I'd recommend that we make var,function and class all behave the same
way.
Does any of the above change if enclosed in a package block? I presume
the class declaration should
be hoisted to the top of the package block. But still, the
initialization remain inline where the
class was declared.
Michael
-----Original Message----- From: es4-discuss-bounces at mozilla.org [mailto:es4-discuss-bounces at mozilla.org] On Behalf Of Michael O'Brien Sent: 15. april 2008 15:06 To: Jeff Dyer Cc: es4-discuss Discuss; Jon Zeppieri Subject: Re: Declarations
Jeff,
Can I tease out a bit more detail. I'm not sure I agree with what the correct answer should be.
Lars raised the issue with "var" a while back and I think, if my memory serves me, the conclusion was that the variable should be hoisted to the top of the var block, but the initialization statement should execute in place.
ie.
=> declaration for y hoisted to here print(y) // Y should exist here but be null x = 1 var y = x // Assigment from x remains here
If the above is true for variables, should we not have the same rules
for functions and for classes? ie. shouldn't class static initialization code remain inline
where the class is defined? I'd recommend that we make var,function and class all behave the same
way.
They don't work the same way, in ES3.
IMO method init needs to be hoisted in classes like function init is in ES3. I think this is important for implementations with vtables.
Classes are compile-time entities (with types and namespaces) and may need to be privileged that way, in initialization terms.
More later.
Here is a confusing example that bears it out.
var x = 1 print("x: " + x)
var y = Shape.z print("y: " + y)
class Shape { public static var z = x print("z: " + z) }
Currently es4 (and ejs) print: x: 1 y: undefined z: 1
ASC prints: z: undefined x: 1 y: undefined
NOTE: both values and order of execution are different.
I prefer the current es4 behavior because static class initialization
code can predictably
use lexically scoped values. And it behaves like var declarations.
Michael O'Brien
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?
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.
Waldemar
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
Question about declarations:
Consider:
print(Shape.x) public class Shape { public static var x = 1; } print(Shape.x)
fun() function fun() { print("fun"); }
In the RI this prints:
undefined 1 fun
In ASC this prints: 1 1 fun
What happens in the RI is the class declaration seems to occur where
it is coded. It is not being hoisted to the top of the enclosing var block. Whereas the function
declaration is and thus can be called before its declaration.
Is this an RI bug or just a divergence from AS3?
Michael