Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Scope Behaviour changed ?

3 views
Skip to first unread message

Gilles Dumortier

unread,
Nov 3, 1999, 3:00:00 AM11/3/99
to
The following code is not working any more. Seems to be related to scope
?! Any idea ? I use JS dated of 29 September 99.

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


Waldemar Horwat

unread,
Nov 3, 1999, 3:00:00 AM11/3/99
to mozill...@mozilla.org
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();

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

Gilles Dumortier

unread,
Nov 4, 1999, 3:00:00 AM11/4/99
to
Waldemar Horwat wrote:

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

Waldemar Horwat

unread,
Nov 4, 1999, 3:00:00 AM11/4/99
to dg...@ieee.org
At 8:44 AM +0100 11/4/99, Gilles Dumortier wrote:
>Waldemar Horwat wrote:
>
> > 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

Gilles Dumortier

unread,
Nov 5, 1999, 3:00:00 AM11/5/99
to
Waldemar Horwat wrote:

> 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 ?

Brendan Eich

unread,
Nov 5, 1999, 3:00:00 AM11/5/99
to dg...@ieee.org
> > 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 ?

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


Waldemar Horwat

unread,
Nov 5, 1999, 3:00:00 AM11/5/99
to Brendan Eich
Brendan:

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

Brendan Eich

unread,
Nov 7, 1999, 3:00:00 AM11/7/99
to Waldemar Horwat
> 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:

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

Brendan Eich

unread,
Nov 17, 1999, 3:00:00 AM11/17/99
to Waldemar Horwat
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

Brendan Eich

unread,
Nov 18, 1999, 3:00:00 AM11/18/99
to
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".
In case my mumblings are unclear, I was referring to three function-defining cases or forms:
  1. Function statements, which are top-level named functions: function f(){}.
  2. Function expressions: f = function(){}, etc.
  3. Function expression-statements: the "then" part of if (0) function f(){}, e.g.
Waldemar had the foresight to forbid case 3 in ECMA Edition 3, so that implementations may be extended to create a superset.  That makes me very happy!

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
 
 

0 new messages