if (some condition) {
function test()
{
...
}
}
...
test(); // <- ReferenceError: test is unknown.
--
Gilles Dumortier
mailto:dg...@ieee.org or http://www.ObHack.com
Pour avoir de bonnes idées, il faut avoir beaucoup d'idées et rejeter
les mauvaises - Linus Paulin
Let's take a look at a concrete example:
if (0) {
function test1() {return "Test 1";}
}
if (1) {
function test2() {return "Test 2";}
}
test1();
test2();
Navigator 4.x allows both calls to test1() and test2(). Allowing the
call to test1() is clearly wrong and will break JavaScript 2.0. I
think a case could be made for allowing the call to test2(), provided
it takes place after test2 is defined. In other words, the following
should not be allowed:
test2();
if (1) {
function test2() {return "Test 2";}
}
The reason for that is that test2 could make use of other variables
introduced by a with or a catch clause, and there is no way to
determine these variables until the definition of test2 is executed.
If we do this extension, we should make sure that the following works
properly:
var o = {x: "Test 3"};
if (1) {
with (o) {
function test3() {return x;}
}
}
test3();
Waldemar
> This is somewhat of a conundrum. First of all, the code is invalid
> under the ECMA Edition 3 proposed standard -- function statements are
> not allowed anywhere except at the top level of a program or another
> function. Given that, in what cases can we make a Netscape-specific
> ECMA extension that allows the code to work?
>
> Let's take a look at a concrete example:
>
> if (0) {
> function test1() {return "Test 1";}
> }
> if (1) {
> function test2() {return "Test 2";}
> }
>
> test1();
> test2();
Concrete sample would be :
if (0) {
function test1() {return "Test 1 - version 1";}
}
if (1) {
function test1() {return "Test 1 - version 2";}
}
test1();
I don't understand why we can't support this given we have no pre-processor.
This is how I expect that it will work in JavaScript 2.0, barring any
committee dissension. However, it's illegal in the final draft of
the ECMAScript Edition 3 standard and in JavaScript 1.5 (unless we
change it at the last minute). JavaScripts prior to 1.5 (such as the
one in Navigator 4.7) allow the syntax but don't process it
correctly. For example, try reversing the polarity of the example:
if (1) {
function test1() {return "Test 1 - version 1";}
}
if (0) {
function test1() {return "Test 1 - version 2";}
}
test1();
You'll still get version 2, which is incorrect.
>--
>Gilles Dumortier
>mailto:dg...@ieee.org or http://www.ObHack.com
>Pour avoir de bonnes idées, il faut avoir beaucoup d'idées et rejeter les
>mauvaises - Linus Paulin
Waldemar
> This is how I expect that it will work in JavaScript 2.0, barring any
> committee dissension. However, it's illegal in the final draft of
> the ECMAScript Edition 3 standard and in JavaScript 1.5 (unless we
> change it at the last minute).
Any chance you implement this for JS 1.5 ?
> JavaScripts prior to 1.5 (such as the
> one in Navigator 4.7) allow the syntax but don't process it
> correctly. For example, try reversing the polarity of the example:
Are you saying that the JS engine is compiling the code inside the dead branch ?
I'll take a look at fixing this over the weekend, unless someone wants dibs.
> > JavaScripts prior to 1.5 (such as the
> > one in Navigator 4.7) allow the syntax but don't process it
> > correctly. For example, try reversing the polarity of the example:
>
> Are you saying that the JS engine is compiling the code inside the dead branch ?
Yes, compiling but not executing. The bug is that the function name was bound into
its static scope object by the compiler. That bug is fixed in Mozilla, per ECMA ed
3, and (obviously) at the loss of the ability to define named functions conditially
such that the name is visible beyond the scope of the named function expression.
/be
How are you planning to fix this? There are two plausible JS2.0
behaviors here, and I feel that we are at a point where we may choose
one:
A. Make the function name available at the top level (or at the
enclosing function scope if nested inside a function), but only after
the declaration is *executed*. [This is equivalent to stating that
the default prefix (see
http://www.mozilla.org/js/language/js20/declarations.html but ignore
everything after "Fix this...") for functions is "box".] This is
similar to JS1.x in that functions leak to the enclosing "box" scope
just like variables but differs in that function (other than ones at
the top level of that box, which are grandfathered) declarations take
effect only when they are executed.
B. Make the function name available in the local block at the time
the block is entered. [This is equivalent to stating that the
default prefix for functions is "local".] This is the dual of choice
A -- it is similar to JS1.x in that function declarations take effect
only when their block is entered but differs in that function
declarations are block-local rather than box-local.
Both A and B are strict supersets of ECMAScript Edition 3.
To keep things simple for now, JS2.0 currently only allows
declarations immediately inside blocks, as opposed to in compound
statements. To illustrate, the following is legal:
if (expr) {
function foo() {...}
}
but the following is not because the declaration of foo is in a
compound statement as opposed to a block:
if (expr)
function foo() {...}
I'll take a look at relaxing this restriction in the future. For
now, var declarations would be grandfathered from JS1.x.
Waldemar
I had A in mind. JS1.x avoids block locals except for catch blocks, and the
(broken) behavior of functions in compound statements up till 1.5 has bound names
in box, not block, scope -- if I understand box correctly. I'd rather not add
more uses of block scope in JS1.x, if it can be helped.
/be
That's not right. You're confusing function expressions with function statements.Worse, I missed something you snuck into ECMA Edition 3: expression statements may not begin with function, so you've reserved exactly the syntax Gilles wants to use (function-defining whole-expression statement in then part of if statement), which I was trying to implement. Thanks!
My implementation attempt was all wrong, and I've gone back to the previous version for the moment. Now that I know that you reserved syntax for an expression statement consisting entirely of a function definition, I can easily whack the JS engine to do this "third case".
/be
My implementation attempt was all wrong, and I've gone back to the previous version for the moment. Now that I know that you reserved syntax for an expression statement consisting entirely of a function definition, I can easily whack the JS engine to do this "third case".
I've checked in changes to js/src that implement case 3. Also, I've extended constant folding trivially to eliminate dead branches of if and if-else statements and ?: expressions. So you can now wrap not-ready-for-prime-time or past-their-prime functions in "if (0) {" and "}", and no bytecode will be generated for those functions.
More to do: eliminate Closure per ECMA ed. 3, using cloned Function object lightweights that share the same (heavyweight) JSScript; speed up closure calling by reducing Call object overhead; finish hiding the Call object (ECMA has always hidden activation objects; JS has not).
People should holler if they're actually using Closure as a constructor, even if only in constructor === Closure tests.
/be