Newly revised Section 10 for ES3.1.

# Allen Wirfs-Brock (16 years ago)

I've just finished reworking section 10 to better accommodate block scoped function declarations and const statements. In the course of this I had to make various decisions about the semantics. The primary purpose of this message is to provide visibility to those decisions and to get feedback on them.

In introducing const statements and block scoped function declaration I tried to apply two over-riding principles:

  1. Anything that is valid to do in ES3 continues to have the exact same semantics.
  2. Anything thing that is new (or non-standard) and would not be valid in ES3 should have a semantics that is rational and consistent with a future introduction of block scoped Let variable bindings

Here are the results: All var declarations continue to be hoisted to "top-level" execution context. Vars never have block level scope or extent. ("top-level" mean the global code, eval code, or the top-level of a function.

Function declarations and const declarations are processed in parallel within a lexical contour (top-level or block). Neither has precedence over the other, unlike the manner in which function declarations take precedence over formal parameters in ES3.

A "top-level" function declaration over-writes any like-named formal parameters or preceding like-named function declarations. This is an ES3 semantics. "Top-level" function declarations are writable. Subsequent declarations or assignments may change their value. This is an ES3 semantics.

A "top-level" const declaration may not have the same name as a formal parameter or any other "top-level" declaration (including consts, vars, and functions). Since consts are new, this is a new semantics.

Const and function declarations within blocks must be uniquely named, such a declaration may not over-write a preceding declaration in the same block and an attempt to do so is a syntax error. Such declarations, of course, shadow any like named declarations in enclosing scopes. Since consts and function declarations in blocks are new, this is a new semantics.

For scoping purposes, const and function declarations are "hoisted" to the top of their defining block. There may be only one, consistent binding of a name within a block. Functions are initialized on block entry, consts are initialized when they are reached in execution flow. Accessing the value of a const before it is initialized throws an exception. Since consts and function declarations in blocks are new, this is a new semantics.

Within in a block, function declarations are read-only bindings. Since declarations in blocks are new, this is a new semantics.

Can anybody from ES4 comment on how closely this matches the current ES4 spec for block scoped consts and nested function declarations.

In the course of this, I noticed a number of conditions that plausibly might be restricted in the cautious subset, but currently aren't specified as such:

  •    Illegal for a function to have duplicately named formal parameters
    
  •    Illegal for a function to contain a top level function declaration with a function name that is the same as a formal parameter.
    
  •    Illegal to have multiple top level function declarations for the same function name
    
  •    Illegal to have a function declaration with the same name as var declaration.
    
  •    Illegal for a function to contain a var declaration with the same name as a formal parameter.
    
  •    Illegal to assign to a top-level function name.
    

Does anybody want to advocate for including these restrictions in the cautious subset.

The following is the revised version of section 10. Review by additional eyeballs would be appreciated. 10 Execution Contexts

When control is transferred to ECMAScript executable code, control is entering an execution context. Active execution contexts logically form a stack. The top execution context on this logical stack is the running execution context.

10.1 Definitions 10.1.1 Function Objects

There are two types of Function objects:

Program functions are defined in source text by a FunctionDeclaration or created dynamically either by using a FunctionExpression or by using the built-in Function object as a constructor.

Internal functions are built-in objects of the language, such as parseInt and Math.exp. An implementation may also provide implementation-dependent internal functions that are not described in this specification. These functions do not necessarily contain executable code defined by the ECMAScript grammar, in which case they are excluded from this discussion of execution contexts.

10.1.2 Types of Executable Code

There are five types of ECMAScript executable code:

Global code is source text that is treated as an ECMAScript Program.. The global code of a particular Program does not include any source text that is parsed as part of a Block or of a FunctionBody except that it does include the code of any VariableDeclaration that is parsed as part of such a Block or as part of a Block nested at any level within such a Block.

Eval code is the source text supplied to the built-in eval function. More precisely, if the parameter to the built-in eval function is a string, it is treated as an ECMAScript Program. The eval code for a particular invocation of eval is the global code portion of the string parameter. The eval code for a particular invocation of eval does not include any source text that is parsed as part of a Block or a FunctionBody except that it does include the code of any VariableDeclaration that is parsed as part of such a Block or as part of a Block nested at any level within such a Block.

Function code is source text that is parsed as part of a FunctionBody. The function code of a particular FunctionBody does not include any source text that is parsed as part of a Block or a FunctionBody except that it does include the code of any VariableDeclaration that is parsed as part of such a Block or as part of a Block nested at any level within such a Block.

Function code also denotes the source text supplied when using the built-in Function object as a constructor. More precisely, the last parameter provided to the Function constructor is converted to a string and treated as the FunctionBody. If more than one parameter is provided to the Function constructor, all parameters except the last one are converted to strings and concatenated together, separated by commas. The resulting string is interpreted as the FormalParameterList for the FunctionBody defined by the last parameter. The function code for a particular instantiation of a Function does not include any source text that is parsed as part of a nested FunctionBody. The function code for a particular instantiation of a Function does not include any source text that is parsed as part of a Block or a FunctionBody except that it does include the code of any VariableDeclaration that is parsed as part of such a Block or as part of a Block nested at any level within such a Block.

Lexical Block code is the source code that that is parsed as the StatementList of a Block. The lexical block code of a particular StatementList does not include any source text that is parsed as part of a nested FunctionBody.

10.1.2.3 Applying Usage Subsets to Executable code

Each occurence of one of these types of code may be restricted to use a defined subset of the complete ECMAScript language.

  •  Global code is unrestricted unless the Program that defines the code includes a UseSubsetDirective.
    
  •  Eval code inherits the restrictions of the execution context in which the eval operator appears, but its execution context may be further restricted if the Program that defines the eval code includes a UseSubsetDirective. In that case, the restrictions of the execution context are the union of the restrictions of the inherited execution context and the restrictions specified by the UseSubsetDirective. Such a unioning of restrictions is the equivalent of intersecting the specified usage subsets.
    
  •  Function code made by evaluating a FunctionDeclaration or a FunctionExpression, function code supplied as the last argument to the Function constructor, and lexical block code all  inherit the restrictions of the execution context in which the evaluation occurs.
    

10.1.3 Environment Bindings Instantiation

Every execution context has associated with it an environment object. For all kinds of execution contexts, constants and functions declared in the source text are added as properties of the environment object. For global code, eval code, and function code variables declared in the source text are also added as properties of the environment object . For function code, parameters are added as properties of the environment object.

Which object is used as the environment object and what attributes are used for the properties depends on the type of code, but the remainder of the behaviour is generic. On entering an execution context, the properties are bound to the environment object in the following order:

For function code: for each formal parameter, as defined in the FormalParameterList, create a named data property of the environment object whose name is the Identifier and whose attributes are determined by the type of code. The values of the parameters are supplied by the caller as arguments to [[Call]]. If the caller supplies fewer parameter values than there are formal parameters, the extra formal parameters have value undefined. If two or more formal parameters share the same name, hence the same property, the corresponding property is given the value that was supplied for the last parameter with this name. If the value of this last parameter was not supplied by the caller, the value of the corresponding property is undefined.

For lexical block code: if the lexical block has any block parameters, create for each block parameter a named data property of the environment object whose name, value, are determined by evaluation context of the Block and whose attributes are {[[Writable]]: true, [[Enumerable]]: false, [[Flexible: false]]}. Only a TryStatement creates lexical block contexts with block parameters.

For all of the FunctionDeclaration and ConstantDeclaration in the code perform the following algorithm. Semantically, this step must follow the creation of FormalParameterList or block parameter properties:

  1.        Let CTX be the current execution context and its associated environment object.
    
  2.        For each FunctionDeclaration and ConstantDeclaration, D in the code in source code order,
    

a. Let N be the Identifer in D.

b. If D is a ConstantDeclaration then

                                       i.If CTX already contains a property named N, throw a SyntaxError exception.

                                     ii.Create a named data property in CTX whose name is N, whose [[Const]] attribute is Unitialized, whose [[Writable]] attribute is false,  and whose value is set to undefined.

c. If D is a FunctionDeclaration then

                                       i.If CTX already contains a property named N, then
  1. If CTX is the execution context of a Block, throw a SyntaxError exception.

  2. If the existing property has a [[Const]] attribute, throw a SyntaxError exception otherwise the value and attributes of the existing property will be replaced by the actions of step 2cii below.

                                     ii.    Create a named data property in CTX whose name is N and whose value is the result returned by creating a Function object as described in 13.
    

d. Other attributes of the named data property are determined by the type of code

For execution contexts that are not lexical blocks: For each VariableDeclaration or VariableDeclarationNoIn in the code (including VariableDeclarations contained within Blocks that are within the code), create a property of the environment object whose name is the Identifier in the VariableDeclaration or VariableDeclarationNoIn, whose value is undefined and whose attributes are determined by the type of code. If there is already a property of the environment object with the name of a declared variable and the property has a [[Const]] attribute throw a SyntaxError exception, otherwise the value of the existing property and its attributes are not changed. Semantically, this step must follow the creation of the FormalParameterList and the FunctionDeclaration and ConstantDeclaration properties. In particular, if a declared variable has the same name as a declared function or formal parameter, the variable declaration does not disturb the existing property.

10.1.3.1 Usage Subset Restrictions

When defined within an execution context subset restricted to the cautious subset, a function may not have two or more formal parameters that have the same name. An attempt to create a such a function with conflicting parameters names will fail, either statically, if expressed as a FunctionDeclaration or FunctionExpression, or dynamically by throwing a SyntaxError exception, if expressed in a call to the Function constructor.

10.1.4 Scope Chain and Identifier Resolution

Every execution context has associated with it a scope chain. A scope chain is a list of objects that are searched when evaluating an Identifier. When control enters an execution context, a scope chain is created and populated with an initial set of objects, depending on the type of code. During execution within an execution context, the scope chain of the execution context is affected only by Blocks, with statements (see 12.10) and catch clauses (see 12.14).

During execution, the syntactic production PrimaryExpression : Identifier is evaluated using the following algorithm:

  1. Get the next object in the scope chain. If there isn't one, go to step 5.

  2. Call the [[HasProperty]] method of Result(1), passing the Identifier as the property name.

  3. If Result(2) is true, return a value of type Reference whose base object is Result(1) and whose property name is the Identifier.

  4. Go to step 1.

  5. Return a value of type Reference whose base object is null and whose property name is the Identifier.

The result of evaluating an identifier is always a value of type Reference with its member name component equal to the identifier string.

10.1.5 Global Object

There is a unique global object (15.1), which is created before control enters any execution context. Initially the global object has the following properties:

Standard built-in objects such as Math, String, Date, parseInt, etc. These have attributes { [[Enumerable]]: false }.

Additional host defined properties. This may include a property whose value is the global object itself; for example, in the HTML document object model the window property of the global object is the global object itself.

As control enters execution contexts, and as ECMAScript code is executed, additional properties may be added to the global object and the initial properties may be changed.

10.1.6 Activation Object

When control enters an execution context for function code or a lexical block, an object called the activation object is created and associated with the execution context.

If the execution context is for function code, the activation object is initialised with a property with name arguments and attributes { [[Writable]]: true, [[Enumerable]]: false, [[Flexible]]: false }. The initial value of this property is the arguments object described below.

The activation object is then used as the environment object for the purposes of environment bindings instantiation.

The activation object is purely a specification mechanism. It is impossible for an ECMAScript program to access the activation object. It can access members of the activation object, but not the activation object itself. When the call operation is applied to a Reference value whose base object is an activation object, null is used as the this value of the call.

10.1.6.1 Usage Subset cautious Restrictions

For functions defined within an execution subset restricted to the cautious subset, the activation object is only initialized with an "arguments" property if the function mentions "arguments" freely in its body. In which case the "arguments" property is initialized with attributes {[[Writable]]: false, [[Enumerable]]: false, [[Flexible]]: false}.

10.1.7 This

There is a this value associated with every active execution context. The this value depends on the caller and the type of code being executed and is determined when control enters the execution context. The this value associated with an execution context is immutable.

10.1.8 Arguments Object

When control enters an execution context for function code, an arguments object is created (see above) and initialised as follows:

The value of the internal [[Prototype]] property of the arguments object is the original Array prototype object, the one that is the initial value of Array.prototype (see 15.4.3.1).

A property is created with name callee and property attributes { [[Writable]]: false, [[Enumerable]]: false, [[Flexible]]: false }. The initial value of this property is the Function object being executed. This allows anonymous functions to be recursive.

A property is created with name length and property attributes { [[Enumerable]]: false }. The initial value of this property is the number of actual parameter values supplied by the caller.

For each non-negative integer, arg, less than the value of the length property, a property is created with name ToString(arg) and property attributes { [[Writable]]: true, [[Enumerable]]: false, [[Flexible]]: false }. The initial value of this property is the value of the corresponding actual parameter supplied by the caller. The first actual parameter value corresponds to arg = 0, the second to arg = 1, and so on. In the case when arg is less than the number of formal parameters for the Function object, this property shares its value with the corresponding property of the activation object. This means that changing this property changes the corresponding property of the activation object and vice versa.

10.1.8.1 Usage Subset cautious Restrictions

For functions defined within an execution subset restricted to the cautious subset, an arguments object is only created if the function mentions "arguments" freely in its body.

If a arguments object is created, a callee property is not created.

The arguments object does not share properties with the activation object. Changing the value of a arguments object property does not change the value of the corresponding activation object property and vice versa.

10.2 Entering An Execution Context

Every function and constructor call enters a new execution context, even if a function is calling itself recursively. Every evalution of a Block enters enters a new execution context which is exited when the block evaluation completes. Every return exits an execution context. A thrown exception, if not caught, may also exit one or more execution contexts.

When control enters an execution context, the scope chain is created and initialised, environment bindings instantiation is performed, and the this value is determined.

The initialisation of the scope chain, environment bindings instantiation, and the determination of the this value depend on the type of code being entered.

10.2.1 Global Code

The scope chain is created and initialised to contain the global object and no others.

Environment bindings instantiation is performed using the global object as the environment object and using property attributes { [[Writable]]: true, [[Enumerable]]: true, [[Flexible]]: false }.

The this value is the global object.

10.2.2 Eval Code

When control enters an execution context for eval code, the previous active execution context, referred to as the calling context, is used to determine the scope chain, the environment object, and the this value. If there is no calling context, then initialising the scope chain, environment bindings instantiation, and determination of the this value are performed just as for global code.

The scope chain is initialised to contain the same objects, in the same order, as the calling context's scope chain. This includes objects added to the calling context's scope chain by Blocks, with statements and catch clauses.

Environment bindings instantiation is performed using the calling context's environment object and using the property attributes { [[Writable]]: true, [[Enumerable]]: true, [[Flexible]]: true }.

The this value is the same as the this value of the calling context.

10.2.2.1 Usage Subset cautious Restrictions

If either the execution context for the eval code or the execution context in which the eval operator was executed is subset restricted to the cautious subset, the eval code cannot instantiate variables, functions, or constants in the lexical context of its eval operator.

Instead, a new environment object is created and appended to the head of the calling context's scope chain and that environment object is used for environment bindings instantiation of the eval code.

10.2.3 Function Code

The scope chain is initialised to contain the activation object followed by the objects in the scope chain stored in the [[Scope]] property of the Function object.

Environment bindings instantiation is performed using the activation object as the environment object and using property attributes { [[Writable]]: true, [[Enumerable]]: true, [[Flexible]]: false }.

The caller provides the this value.

10.2.4 Lexical Block Code

A new activation object is created for use as the environment object. The scope chain is initialised to contain the new activation object followed by the objects in the current execution context's scope chain.

Environment bindings instantiation is performed using the new object as the environment object and using property attributes { [[Writable]]: false, [[Enumerable]]: false, [[Flexible]]: false }.

The this value is the same as the this value of the previously current context.

# Maciej Stachowiak (16 years ago)

On Jul 9, 2008, at 5:16 PM, Allen Wirfs-Brock wrote:

Const and function declarations within blocks must be uniquely
named, such a declaration may not over-write a preceding declaration
in the same block and an attempt to do so is a syntax error. Such
declarations, of course, shadow any like named declarations in
enclosing scopes. Since consts and function declarations in blocks
are new, this is a new semantics.

Although the standard does not allow block-level function
declarations, the following will parse and give identical results in
all four of the major browsers (it will alert "2"):

<script>

function g() { if (true) { function f() { alert("1"); } function f() { alert("2"); } } f(); } g(); </script>

This example will interoperably alert "1":

<script>

function g() { if (true) { function f() { alert("1"); } } f(); } g(); </script>

As I understand it, your proposal would make the first example a
syntax error and the second a runtime error (unless a global function
named f is defined).

I know from experience that sites do accidentally depend on the
intersection of the different IE and Firefox extensions for block- level function declarations (and the Safari and Opera attempts to
emulate them). Do you have evidence that leads you to conclude that
your proposed behavior is compatible with the Web? I am almost certain
it is not.

, Maciej

# Mike Shaver (16 years ago)

2008/7/9 Maciej Stachowiak <mjs at apple.com>:

Although the standard does not allow block-level function declarations

I'd understood that, while ES3 didn't specify such declarations, it was not a violation of the standard to have them. I agree with your assessment of the compatibility impact, certainly.

Mike

# Garrett Smith (16 years ago)

2008/7/9 Allen Wirfs-Brock <Allen.Wirfs-Brock at microsoft.com>:

I've just finished reworking section 10 to better accommodate block scoped function declarations and const statements. In the course of this I had to make various decisions about the semantics. The primary purpose of this message is to provide visibility to those decisions and to get feedback on them.

In introducing const statements and block scoped function declaration I tried to apply two over-riding principles:

  1. Anything that is valid to do in ES3 continues to have the exact same semantics.

  2. Anything thing that is new (or non-standard) and would not be valid in ES3 should have a semantics that is rational and consistent with a future introduction of block scoped Let variable bindings

A FunctionDeclaration in a block is not valid in ES3, so apparently that is the reason for your note.

Here are the results:

All var declarations continue to be hoisted to "top-level" execution context. Vars never have block level scope or extent.

("top-level" mean the global code, eval code, or the top-level of a function.

This sentence is confusing. eval code is not necessarily global.

Reading further down, it seems that you mean to define "top-level" as a new term for what we already know to mean [[Scope]] and then to define a block scope term. It seems that you are aiming to differentiate between function scope and a new type of "block" scope.

If my assumption is correct, then creating a new type of "block" scope does not necessitate changing the term [[Scope]] to "top level". [[Scope]] can still be [[Scope]] and block scope can be called whatever you like ([[Block]], [[BlockScope]], et c)

Does this sound reasonable?

Function declarations and const declarations are processed in parallel within a lexical contour (top-level or block). Neither has precedence over the other, unlike the manner in which function declarations take precedence over formal parameters in ES3.

A "top-level" function declaration over-writes any like-named formal parameters or preceding like-named function declarations. This is an ES3 semantics.

The global object cannot have parameters, so I should probably assume that top-level means the same thing as [[Scope]] in ES3.

When you use a made-up word like "over-writes" it is unclear. It could mean any of:

  1. replaces the value
  2. replaces the value and attributes
  3. shadows a property in the scope chain (some do use the term "override" in this way)

It is not clear what you mean.

"Top-level" function declarations are writable. Subsequent declarations or assignments may change their value. This is an ES3 semantics.

I'm not sure how you understand it, but let me explain how I understand it, and maybe you'll see why what you've written is confusing to me.

A FunctionDeclaration creates a property on the Variable object (or replaces the value and attributes if it it already exists).

To quote the relevant part of the spec:

| 10.1.3 Variable Instantiation | | Every execution context has associated with it a variable object. | Variables and functions declared in the source text are added as | properties of the variable object. For function code, parameters | are added as properties of the variable object.

bclary.com/2004/11/07/#a-10.1.3

[snip]

Within in a block, function declarations are read-only bindings. Since declarations in blocks are new, this is a new semantics.

IOW, a FunctionDeclaration creates a property of the BlockScope with the attributes {ReadOnly, DontDelete}

In the course of this, I noticed a number of conditions that plausibly might be restricted in the cautious subset, but currently aren't specified as such:

· Illegal for a function to have duplicately named formal parameters

Is this a problem in ES3?

· Illegal for a function to contain a top level function declaration with a function name that is the same as a formal parameter.

· Illegal to have multiple top level function declarations for the same function name

· Illegal to have a function declaration with the same name as var declaration.

· Illegal for a function to contain a var declaration with the same name as a formal parameter.

· Illegal to assign to a top-level function name.

Five sensible suggestions, but they would be incompatible with ES3.0 (see quote above).

[snip]

10.1.6.1 Usage Subset cautious Restrictions

For functions defined within an execution subset restricted to the cautious subset, the activation object is only initialized with an "arguments" property if the function mentions "arguments" freely in its body. In which case the "arguments" property is initialized with attributes {[[Writable]]: false, [[Enumerable]]: false, [[Flexible]]: false}.

That would be incompatible with ES3. Arguments is not ReadOnly (or "Writable:false"). (Doesn't seem like it would create a problem but this violate your "rule 1")

Valid ES3:

function z() { arguments = 1; return arguments; }

z();

Garrett

# Mark S. Miller (16 years ago)

On Wed, Jul 9, 2008 at 6:47 PM, Mike Shaver <mike.shaver at gmail.com> wrote:

2008/7/9 Maciej Stachowiak <mjs at apple.com>:

Although the standard does not allow block-level function declarations

I'd understood that, while ES3 didn't specify such declarations, it was not a violation of the standard to have them. I agree with your assessment of the compatibility impact, certainly.

I believe the prohibition is in the ES3 syntax definition.

# Mark S. Miller (16 years ago)

IIUC, these examples work the same in Allen's proposal as the do in ES4. If this does break the web, doesn't ES4 have exactly the same problem?

# Brendan Eich (16 years ago)

On Jul 9, 2008, at 6:54 PM, Mark S. Miller wrote:

On Wed, Jul 9, 2008 at 6:47 PM, Mike Shaver <mike.shaver at gmail.com>
wrote: 2008/7/9 Maciej Stachowiak <mjs at apple.com>:

Although the standard does not allow block-level function
declarations

I'd understood that, while ES3 didn't specify such declarations, it was not a violation of the standard to have them. I agree with your assessment of the compatibility impact, certainly.

I believe the prohibition is in the ES3 syntax definition.

ES3 chapter 16:

An implementation shall report all errors as specified, except for
the following: • An implementation may extend program and regular expression syntax.
To permit this, all operations (such as calling eval, using a regular expression literal, or using the
Function or RegExp constructor) that are allowed to throw SyntaxError are permitted to exhibit implementation-defined
behaviour instead of throwing SyntaxError when they encounter an implementation-defined extension to the
program or regular expression syntax.

As Maciej notes, all four browsers extend syntax to support functions
in sub-statement contexts. There's no prohibition given the chapter
16 language allowing such extensions. Is ES3.1 specifying
"reality" (intersection semantics), or something not in the
intersection or union of existing browsers' syntax and semantics,
that is restrictive and therefore not compatible without a similar
allowance for extensions?

Chapter 16 is important to carry forward in any 3.1 or 4 successor
edition.

# Brendan Eich (16 years ago)

On Jul 9, 2008, at 6:58 PM, Mark S. Miller wrote:

Hi Maciej, IIUC, these examples work the same in Allen's proposal
as the do in ES4. If this does break the web, doesn't ES4 have
exactly the same problem?

The idea for ES4 was to change the meaning of function sub-statements
only under opt-in versioning. Implementations would do whatever they
do today without an explicit type="application/ecmascript;version=4"
or equivalent "application/javascript;version=2" on the script tag.

# Mark S. Miller (16 years ago)

On Wed, Jul 9, 2008 at 7:02 PM, Brendan Eich <brendan at mozilla.org> wrote:

On Jul 9, 2008, at 6:58 PM, Mark S. Miller wrote:

Hi Maciej, IIUC, these examples work the same in Allen's proposal as the

do in ES4. If this does break the web, doesn't ES4 have exactly the same problem?

The idea for ES4 was to change the meaning of function sub-statements only under opt-in versioning. Implementations would do whatever they do today without an explicit type="application/ecmascript;version=4" or equivalent "application/javascript;version=2" on the script tag.

I had not understood that. I knew that new keywords were switched by the ES4 opt-in, and I have been following what ES4 switches based on strictness, but I probably haven't paid enough attention to ES4 opt-in. Besides keywords, what other elements of ES4 are switched on opt-in rather than strictness? Are all four combinations of opt-in vs strictness possible? Is opt-in per execution context (script) or per global object (frame)? A link to the relevant docs is an adequate answer. Thanks.

# Allen Wirfs-Brock (16 years ago)

Yes, but <script>

function g() { if (true) { function f() { alert("1"); } } Else { function f() { alert("2"); } } f(); } g(); </script>

doesn't yield consistent results across browsers. Even if we can craft a specification that just captured those aspects of block nest function declarations that are identical in the 4 principal browsers would It's not clear that anybody would be very happy with the result. (For example, a function of a given name can occurs in at most one conditionally executed block). Arguably, one "advantage" of my proposal is that it equally breaks all the existing implementations of block nested function declarations.

From: Maciej Stachowiak [mailto:mjs at apple.com] Sent: Wednesday, July 09, 2008 6:34 PM To: Allen Wirfs-Brock Cc: es3.x-discuss at mozilla.org; es4-discuss at mozilla.org; Mark S. Miller; Herman Venter; Pratap Lakshman (VJ#SDK); Douglas Crockford Subject: Re: Newly revised Section 10 for ES3.1.

On Jul 9, 2008, at 5:16 PM, Allen Wirfs-Brock wrote:

Const and function declarations within blocks must be uniquely named, such a declaration may not over-write a preceding declaration in the same block and an attempt to do so is a syntax error. Such declarations, of course, shadow any like named declarations in enclosing scopes. Since consts and function declarations in blocks are new, this is a new semantics.

Although the standard does not allow block-level function declarations, the following will parse and give identical results in all four of the major browsers (it will alert "2"):

<script>

function g() { if (true) { function f() { alert("1"); } function f() { alert("2"); } } f(); } g(); </script>

This example will interoperably alert "1":

<script>

function g() { if (true) { function f() { alert("1"); } } f(); } g(); </script>

As I understand it, your proposal would make the first example a syntax error and the second a runtime error (unless a global function named f is defined).

I know from experience that sites do accidentally depend on the intersection of the different IE and Firefox extensions for block-level function declarations (and the Safari and Opera attempts to emulate them). Do you have evidence that leads you to conclude that your proposed behavior is compatible with the Web? I am almost certain it is not.

, Maciej

# Mike Shaver (16 years ago)

2008/7/10 Allen Wirfs-Brock <Allen.Wirfs-Brock at microsoft.com>:

Even if we can craft a specification that just captured those aspects of block nest function declarations that are identical in the 4 principal browsers would It's not clear that anybody would be very happy with the result.

It seems like that would be at least as much worth trying as is "make something that's actively incompatible with all 4 browsers", no?

Arguably, one "advantage" of my proposal is that it equally breaks all the existing implementations of block nested function declarations.

I can only presume that you're joking here.

FWIW, this sort of thing is a reason that I'm pretty concerned about ES3.1 getting into an advanced specification state without the benefit of any in-browser implementation.

Mike

# Allen Wirfs-Brock (16 years ago)

I completely agree, chapter 16 needs to carry forward. We don't want to forbid implementations from experimenting with future extensions.

When there has been broad agreement across major implements on an extension (including the full semantics), I think it makes sense to standardize that consensus. If there isn't such agreement, I'm not so sure it makes sense to only standardize the compatible intersection of major implementations as that may not be a useful subset of functionality.

# Allen Wirfs-Brock (16 years ago)

I'm also confused about this. My understanding was, other than perhaps some of the details I was specifically looking for feedback on, that what I specified was generally what ES4 was planning on doing.

From: es4-discuss-bounces at mozilla.org [mailto:es4-discuss-bounces at mozilla.org] On Behalf Of Mark S. Miller Sent: Wednesday, July 09, 2008 7:13 PM To: Brendan Eich Cc: Herman Venter; Douglas Crockford; es3.x-discuss at mozilla.org; es4-discuss at mozilla.org; Pratap Lakshman (VJ#SDK) Subject: Re: Newly revised Section 10 for ES3.1.

On Wed, Jul 9, 2008 at 7:02 PM, Brendan Eich <brendan at mozilla.org<mailto:brendan at mozilla.org>> wrote:

On Jul 9, 2008, at 6:58 PM, Mark S. Miller wrote: Hi Maciej, IIUC, these examples work the same in Allen's proposal as the do in ES4. If this does break the web, doesn't ES4 have exactly the same problem?

The idea for ES4 was to change the meaning of function sub-statements only under opt-in versioning. Implementations would do whatever they do today without an explicit type="application/ecmascript;version=4" or equivalent "application/javascript;version=2" on the script tag.

I had not understood that. I knew that new keywords were switched by the ES4 opt-in, and I have been following what ES4 switches based on strictness, but I probably haven't paid enough attention to ES4 opt-in. Besides keywords, what other elements of ES4 are switched on opt-in rather than strictness? Are all four combinations of opt-in vs strictness possible? Is opt-in per execution context (script) or per global object (frame)? A link to the relevant docs is an adequate answer. Thanks.

# Brendan Eich (16 years ago)

On Jul 9, 2008, at 10:05 PM, Allen Wirfs-Brock wrote:

I’m also confused about this. My understanding was, other than
perhaps some of the details I was specifically looking for feedback
on, that what I specified was generally what ES4 was planning on
doing.

See my reply to Mark citing

doku.php? id=meetings:minutes_mar_27_2008#technical_notes

"[W]hat ES4 was planning on doing" needs to be qualified with "under
the default version" of JS, or under opt-in versioning. Again since
default versions get differing function statement semantics depending
on browser, unless all browsers can afford to break existing browser- specific content, the change to unify on proposed ES4 semantics may
need to be under opt-in version selection only.

If some browsers implemented in a way that happens to work for most
browser-specific content (it's hard to be sure), then perhaps those
implementations could just make the change. But for cross-browser
portability, web scripts would want to select the explicit version
that guarantees the new semantics (and syntax, for that matter) in
all browsers that support that version.

# Allen Wirfs-Brock (16 years ago)

There was two parts to may message, an informal overview of the proposed semantics and the excerpt from the actual "formal" (and I use that term advisedly) specification of the semantics. I was using the term "top-level" in the informal part of the message to refer to code that wasn't in a nested block. It is not intended to be new formal terminology of the specification. It has nothing to do with the [[Scope]] property. I do introduce some new formal terminology but it is all in the specification excerpt, not in the informal overview. [[Scope]] is simply the internal property that is used to capture the lexical environment (the scope chain) that is active when a function object is created.

What I do introduce is a new kind of execution context for lexical blocks and a new kind of activation object that is associated with lexical block execution contexts.

You confusion about the meaning of my informal language reasonably points out the weakness of informal descriptions. Please read the actual rewrite of section 10 and see if you also find it confusing or ambiguous. If so, that's important and something I will try to fix.

Regarding, the "cautious subset" restrictions. By design, they are incompatible with ES3. The cautious subset (or the similar but not yet identical ES4 strict mode" is an Opt-in subset of the ES3.1 language that among other things allows a programmer to request that certain problematic ES3 constructs become illegal and generate errors. Every valid proposed ES3.1 cautious subset program is also a valid program in the full language. However, every valid program in the full language is not necessarily a valid cautious subset program.

# Mark S. Miller (16 years ago)

On Wed, Jul 9, 2008 at 10:35 PM, Allen Wirfs-Brock < Allen.Wirfs-Brock at microsoft.com> wrote:

Every valid proposed ES3.1 cautious subset program is also a valid program in the full language.

I don't think it works to restate the "fail stop subset" notion in terms of validity. Rather, we can say that an ES3.1 cautious program that runs without causing any cautiousness-induced failures will run the same way in the full language. Put another way, Given an alleged ES3.1 cautious program, it will

  • be statically rejected
  • cause a failure by violating a dynamic cautiousness restriction
  • execute as it would in the full ES3.1 language.

For example, the following is a perfectly valid ES3.1 cautious function:

function isCautious() { function foo() {this;} try { foo(); } catch (e) { return true; } return false; }

# Allen Wirfs-Brock (16 years ago)

It seems like that would be at least as much worth trying as is "make

something that's actively incompatible with all 4 browsers", no?

I'd love to see a proposal

I can only presume that you're joking here.

Not really, if you have to change something it may be better to do it in a way that breaks all existing uses rather than just some of them. It isn't obvious that either the FF or IE approach to function declarations in conditional blocks is "better" or more correct. Arguments can be made on both design choices. In such a situation, the best solution may actually be to break both of them rather than breaking only one of them. Particularly, if there is a strong argument that the new design is better than either of the existing ones.

FWIW, this sort of thing is a reason that I'm pretty concerned about

ES3.1 getting into an advanced specification state without the benefit of any in-browser implementation.

You need to have an advance specification state before you can meaningfully test it in an implementation.

# Allen Wirfs-Brock (16 years ago)

This is currently stated in section 4.2.2 of the draft as:

With one exception, an ECMAScript program that is voluntarily limited to a usage subset and which executes without error under the subset's restrictions will behave identically if executed without on any usage subset restrictions. The exception is any situation where the operation of such a program depends upon the actual occurrence and subsequent handling of additional error conditions that are part of the subset.

From: Mark S. Miller [mailto:erights at google.com] Sent: Wednesday, July 09, 2008 10:48 PM To: Allen Wirfs-Brock Cc: Garrett Smith; es4-discuss at mozilla.org; Herman Venter; Pratap Lakshman (VJ#SDK); Douglas Crockford Subject: Re: Newly revised Section 10 for ES3.1.

On Wed, Jul 9, 2008 at 10:35 PM, Allen Wirfs-Brock <Allen.Wirfs-Brock at microsoft.com<mailto:Allen.Wirfs-Brock at microsoft.com>> wrote:

Every valid proposed ES3.1 cautious subset program is also a valid program in the full language.

I don't think it works to restate the "fail stop subset" notion in terms of validity. Rather, we can say that an ES3.1 cautious program that runs without causing any cautiousness-induced failures will run the same way in the full language. Put another way, Given an alleged ES3.1 cautious program, it will

  • be statically rejected
  • cause a failure by violating a dynamic cautiousness restriction
  • execute as it would in the full ES3.1 language.

For example, the following is a perfectly valid ES3.1 cautious function:

function isCautious() { function foo() {this;} try { foo(); } catch (e) { return true; } return false; }

# Mark Miller (16 years ago)

2008/7/9 Allen Wirfs-Brock <Allen.Wirfs-Brock at microsoft.com>:

This is currently stated in section 4.2.2 of the draft as:

With one exception, an ECMAScript program that is voluntarily limited to a usage subset and which executes without error under the subset's restrictions will behave identically if executed without on any usage subset restrictions. The exception is any situation where the operation of such a program depends upon the actual occurrence and subsequent handling of additional error conditions that are part of the subset.

I like and agree with that text. My point exactly is your exception above: a valid program may react to a subset-induced error condition.

ES4 folks,

What are the compatibility relationships between ES4 opt-in, ES4 opt-in strict, ES4 strict, and ES4? I think it's clear that ES4 opt-in strict is a subset of ES4 opt-in. Are there any other subset relationships among them? I hadn't realized till just now how large the gulf might be between ES4 opt-in and ES4. Do opt-in and strict define orthogonal switches? Can opt-in and non-opt-in programs co-exist in the same frame (global object)? We all need to clarify these issues.

# Brendan Eich (16 years ago)

On Jul 9, 2008, at 11:37 PM, Mark Miller wrote:

What are the compatibility relationships between ES4 opt-in, ES4 opt-in strict, ES4 strict, and ES4? I think it's clear that ES4 opt-in strict is a subset of ES4 opt-in.

You have to opt into ES4 to even utter the pragma |use strict|, so
there's no "ES4 strict" without opt-in.

"ES4" without opt-in is also not meaningfully different from the
compatible default version that browsers more-or-less agree on (which
has been called "ES3 + reality", which was one idea for ES3.1).
Keywords new in ES4, even though only contextually reserved under opt- in versioning, would not be reserved in any context in the default
version.

As for new syntax not involving new keywords, and new library APIs,
we have talked about supporting these additions in the default
version, since doing so cannot break existing code. Note that "new
syntax not involving new keywords" does not cover function sub- statements, as noted in this thread -- there, compatibility issues
exist. Also, some implementations have extended ES3 with, e.g., const
-- again not compatibly with ES4 as proposed. So opt-in versioning
may (or may not, depending on browser-specific content) be required
to change the meaning of const or function in a block or other sub- statement context.

Are there any other subset relationships among them? I hadn't realized till just now how large the gulf might be between ES4 opt-in and ES4.

What is "ES4" without opt-in version selection? How could it differ
from <script>...</script> or <script type="application/

javascript">...</script>?

Do opt-in and strict define orthogonal switches? Can opt-in and non-opt-in programs co-exist in the same frame (global object)? We all need to clarify these issues.

Have you read

proposals:versioning

?

# Maciej Stachowiak (16 years ago)

On Jul 9, 2008, at 10:01 PM, Allen Wirfs-Brock wrote:

I completely agree, chapter 16 needs to carry forward. We don't
want to forbid implementations from experimenting with future
extensions.

When there has been broad agreement across major implements on an
extension (including the full semantics), I think it makes sense to
standardize that consensus. If there isn't such agreement, I'm not
so sure it makes sense to only standardize the compatible
intersection of major implementations as that may not be a useful
subset of functionality.

Sure, but your proposal is actively incompatible with all the existing
implementations, because real web content does in fact do things like
this:

if (someConditionThatIsAlwaysTrue) { function someFuncIThoughtWasConditionallyDeclared() { // some code } }

and then the content counts on the function declaration being hoisted.
Your proposal breaks that. It would also in some cases cause parse
errors on content that would currently parse in all the browsers,
meaning that even a mistake in a function that never gets called would
start causing the whole script to fail.

I do not know if it is possible to make a proposal that both is useful
and doesn't break the Web, within the premises of ES3.1. But it seems
to me that a proposal that is almost sure to break the Web would be
unacceptable under the ES3.1 assumptions, and locking it into a spec
without first doing some form of widespread testing seems like a
totally broken process.

I do not believe that ECMA has the "two interoperable implementations"
rule that the IETF and W3C have, but since ECMAScript is a standard of
equal important to the Web, I think we should adopt this rule for any
future edition of ECMAScript. Such a rule is needed precisely to avoid
such casual breakage relative to Web reality. Can we make that a
binding TC39 resolution?

, Maciej

# Brendan Eich (16 years ago)

On Jul 10, 2008, at 12:02 AM, Maciej Stachowiak wrote:

I do not believe that ECMA has the "two interoperable implementations" rule that the IETF and W3C have, but since ECMAScript is a standard of equal important to the Web, I think we should adopt this rule for any future edition of ECMAScript.

Agreed -- I've been saying this, and I'm trying to line up at four
non-reference ES4 implementation efforts.

Such a rule is needed precisely to avoid such casual breakage relative to Web reality. Can we make that a binding TC39 resolution?

It's really up to the TC. Ecma does not have a rule (the w3c has
broken its own rule, as you know). The binding part is the honor
system, not words on paper -- as with any resolution.

# Brendan Eich (16 years ago)

On Jul 10, 2008, at 12:09 AM, Brendan Eich wrote:

On Jul 10, 2008, at 12:02 AM, Maciej Stachowiak wrote:

I do not believe that ECMA has the "two interoperable
implementations" rule that the IETF and W3C have, but since ECMAScript is a
standard of equal important to the Web, I think we should adopt this rule for any future edition of ECMAScript.

Agreed -- I've been saying this, and I'm trying to line up at four non-reference ES4 implementation efforts.

At least four:

SpiderMonkey Rhino ESC+Tamarin MbedThis

Opera is a hoped-for fifth. But this is in the future, along with
draft specs sufficient to prototype, and tests added to today's ES3- ish suites (which seem to have common ancestry in Mozilla's js/tests).

# Brendan Eich (16 years ago)

On Jul 9, 2008, at 11:59 PM, Brendan Eich wrote:

As for new syntax not involving new keywords, and new library APIs, we have talked about supporting these additions in the default version, since doing so cannot break existing code.

This is not true of ES4, although it's true we have talked about
trying to unconditionally add properties. The problem is that if
existing code object-detects a new API property, expecting its own
same-named (but possibly very different) method or value, it could
use an ES4 namesake and go very wrong.

ES4 as proposed uses the ES4 namespace to hide new names from the
default version. Opting into ES4 opens the ES4 namespace. This is
in the docs on ecmascript.org and the draft specs that have
been circulated. There may be problems yet to solve with this
approach, but it's a bona fide attempt to avoid potentially breaking
property additions to standard objects.

# Mark S. Miller (16 years ago)

On Wed, Jul 9, 2008 at 11:59 PM, Brendan Eich <brendan at mozilla.org> wrote:

Have you read

proposals:versioning

?

I had read it, but rereading it in the current context was illuminating. Thanks for the pointer.

Is "current document" the same as "current frame" and "current global object"?

# Mike Shaver (16 years ago)

On Thu, Jul 10, 2008 at 1:48 AM, Allen Wirfs-Brock <Allen.Wirfs-Brock at microsoft.com> wrote:

FWIW, this sort of thing is a reason that I'm pretty concerned about ES3.1 getting into an advanced specification state without the benefit of any in-browser implementation.

You need to have an advance specification state before you can meaningfully test it in an implementation.

Sure, there's an interdependency, but it seems like you wouldn't want to propose something for inclusion into a short-turn spec like ES3.1 unless you'd seen it run somewhere relevant, no? Is there a document somewhere that tracks which ES3.1 features have been implemented in what prototype engine?

Some of the features of ES3.1 (such as the library additions) seem like they are individually into an advanced specification state, so perhaps they're where to start?

Mike

# Mike Shaver (16 years ago)

On Thu, Jul 10, 2008 at 8:54 AM, Sam Ruby <rubys at intertwingly.net> wrote:

Decimal is a library addition. A superset of whatever gets proposed for ES3.1 should be included in ES4. Brendan mentioned four places where ES4 implementation work is either occurring or intended to occur:

SpiderMonkey Rhino ESC+Tamarin MbedThis

I'm quite willing to code (as well as work through the relevant IP issues associated with the implementation itself). Any suggestions on where it would be best for me to start?

I would say that either Spidermonkey or JSCore would be the best places, since they are the ones that are easiest to bring up in a browser for testing of interaction with real-world content.

Mike

# OpenStrat at aol.com (16 years ago)

In a message dated 7/10/2008 3:03:12 A.M. Eastern Daylight Time,
mjs at apple.com writes:

I do not believe that ECMA has the "two interoperable implementations"
rule that the IETF and W3C have, but since ECMAScript is a standard of
equal important to the Web, I think we should adopt this rule for any
future edition of ECMAScript. Such a rule is needed precisely to avoid
such casual breakage relative to Web reality. Can we make that a
binding TC39 resolution?

While it is true that no such rule exists in Ecma, it has been used in work
I am familiar with (optical storage) within TC 31. Early work on MO storage resulted in TC 31 agreeing that at least two implementations must demonstrate interoperability before approval of the standard. This meant that both disk manufacturers and drive manufacturers had to work together to demonstrate that the product resulting from the standard would work together. The committee always followed this rule without question, and the CC and GA of Ecma did not interfere with its implementation.

We can add this subject to discussion at Oslo, but this is a question that I would put to an internal vote of TC 31 since it has wider impact than may be
represented in Oslo.

,

John

**************Get the scoop on last night's hottest shows and the live music scene in your area - Check out TourTracker.com!
(www.tourtracker.com?NCID=aolmus00050000000112)

# OpenStrat at aol.com (16 years ago)

On my last comment, please note that an internal vote would be within TC 39, not TC 31. What hat am I wearing today?

John

**************Get the scoop on last night's hottest shows and the live music scene in your area - Check out TourTracker.com!
(www.tourtracker.com?NCID=aolmus00050000000112)

# Mike Shaver (16 years ago)

On Thu, Jul 10, 2008 at 9:55 AM, Sam Ruby <rubys at intertwingly.net> wrote:

Library additions have less of a concern for interaction with real-world content, but the idea of inserting the code into something that will ultimately ship does appeal to me. If I were to do the work to put this code into SpiderMonkey(*), would you see it being included in some future release of Firefox?

  • Sam Ruby

(*) And it were to prove to be stable and doesn't break the web, and the function were to make some edition of ECMAScript, and yadda, yadda, yadda.

I can't see why not -- we'll certainly be looking to implement forthcoming editions of ECMAScript, and if decimal is a part of it then your code would certainly be helpful!

Mike

# Brendan Eich (16 years ago)

On Jul 10, 2008, at 12:41 AM, Mark S. Miller wrote:

On Wed, Jul 9, 2008 at 11:59 PM, Brendan Eich <brendan at mozilla.org>
wrote: Have you read

proposals:versioning

?

I had read it, but rereading it in the current context was
illuminating. Thanks for the pointer.

Is "current document" the same as "current frame" and "current
global object"?

It turns out that they are coterminous and coextensive, because
closures entrain the global object -- yet the window object as
returned by window.open or accessed otherwise via the DOM must have
persistent object identity -- you can write 'var w = window.open (...);' and no matter how many docs load in w, its object-reference
identity is the same.

This duality requires something called "split windows", where w is
the "outer" window object that persists across navigation, and each
document gets a fresh "inner" window object to use as the ECMA-262
"global object". All browsers do this now (Safari in seed 4 versions,
if I recall Maciej's post here the other week correctly).

# Richard Cornford (16 years ago)

10.1.8 Arguments Object <snip> For each non-negative integer, arg, less than the value of the length property, a property is created with name ToString(arg) and property attributes { [[Writable]]: true, [[Enumerable]]: false, [[Flexible]]: false }. The initial value of this property is the value of the corresponding actual parameter supplied by the caller. The first actual parameter value corresponds to arg = 0, the second to arg = 1, and so on. In the case when arg is less than the number of formal parameters for the Function object, this property shares its value with the corresponding property of the activation object. This means that changing this property changes the corresponding property of the activation object and vice versa.

The provision "that changing this property changes the corresponding property of the activation object and vice versa" implies a potentially long-term linkage between some properties of activation objects corresponding arguments object properties. As functions forming closures can have ongoing access to activation objects and references to arguments objects can be assigned to object properties and variables (and so remain accessible after the function calls for which they were created have finished) this implied long-term linkage could have practical implications. For example:-

function getToy(one, two, three){ var ar = arguments; ar[2] = 7; return ({ setOne:function(x){ // setting the '0' property of the arguments object should // change the value of the - one - formal parameter. ar[0] = x; }, getOne:function(){ return one; }, setTwo:function(x){ two = x; }, getTwo:function(){ return ar[1]; }, getThree:function(){ return three; } }); }

var obj = getToy(1, 2, 3);

obj.setOne(5); obj.setTwo(6); alert( obj.getOne()+'\n'+ obj.getTwo()+'\n'+ obj.getThree() );

  • could be expected to alert 5, 6 and 7, and does in Windows Safari 3 and Opera 9. But IE 6 and Firefox 2, for example, it alerts 1, 2 and 7. There the linkage breaks down outside of the execution context of the initial function call.

A new specification probably should pin down which of these is "correct". It should either reinforce the implication that the linkage is intended to be long term or state the lifespan of the linkage (possibly saying that it cannot be expected to hold past the lifespan of the execution context for which the arguments object was created (thus categorizing longer term linkage as a possible non-standard extension)). I would favour the latter as the inconsistency in existing implementations makes it unlikely that anyone is using this linkage outside of the functions whose calls create the arguments objects, and there is nothing that could be done with this linkage that could not be better (less obscurely) achieved using closures.

# Richard Cornford (16 years ago)

In the course of this, I noticed a number of conditions that plausibly might be restricted in the cautious subset, but currently aren't specified as such: <snip>

  •    Illegal to assign to a top-level function name.
    

Does anybody want to advocate for including these restrictions in the cautious subset.

This last would not be a good idea in a language intended for browser scripting. There are circumstances were code needs to test its environment in order to determine how it should act. In many cases the conditions being tested for will not change while the script is being executed (the nature of a browser's object model will not change while it is executing a script) so repeating the test on each execution of a function is inefficient as the results of the test will always be the same as the first.

One strategy for dealing with that is to have the first call to a function perform the test and so decide which actions should be take in the given environment and, instead of taking those actions directly, assign a new function to replace itself where that new function only takes the chosen action and so avoids the overhead of testing on all subsequent calls to the function. Something like:-

fucntion getSomething(arg){ if(caseOneTest){ getSomething = function(x){ //actions appropriate for case one }; }else if(caseTwoTest){ getSomething = function(x){ //actions appropriate for case two }; }else{ getSomething = function(x){ //actions appropriate for other cases }; } return getSomething(arg); }

It is the ability to do this sort of thing that helps make javascript so well suited to browser scripting.

# Maciej Stachowiak (16 years ago)

(Adding lists back to Cc, which I assume you meant to do)

On Jul 10, 2008, at 5:06 PM, Garrett Smith wrote:

Authors who assume that the function was conditionally declared in IE and Opera (and who knows what else) would be making false assumption.

That's true, but what I have seen in practice is that code can end up
depending on its false assumption being violated, or working by luck.
For example, you see code like:

if (!isIE) { function somethingEssential() { } }

where somethingEssential is then unconditionally called.

If subsequent code relied on that false assumption, and produced intended results, it would be only by coincidence:

if(!isIE && !isOpera) { function a(){ return 0; } } else ( function a(){ return 1; } // IE gets here (coincidence unrelated to
else) }

That would be very lucky programming, because if reversed, it would not produce the same results:

if(isIE && isOpera) { function a(){ return 1; } } else ( function a(){ return 0; } // IE gets here.(coincidence unrelated to
else) }

FunctionDeclarations are processed during variable instantiation, before code execution. IE and Opera (and probably other browsers) would always take the last one because in these environments, it would have the effect of:-

function each(){ return 1; } function each(){ return 0; } if(isIE && isOpera) { } else { }

I do not know if it is possible to make a proposal that both is
useful and doesn't break the Web, within the premises of ES3.1. But it seems to me that a proposal that is almost sure to break the Web would be unacceptable under the ES3.1 assumptions, and locking it into a spec without first doing some form of widespread testing seems like a totally broken process.

Is it possible to know how much breakage would occur?

I don't know, but I am pretty sure it would be a non-zero amount. I
think it is up to proponents of this proposal to somehow demonstrate
that the level of breakage would be low enough; the presumption should
be in favor of compatibility.

Web scripts that attempt to work across IE and Mozilla that use a FunctionDeclaration in a Block either exhibit a bug or get lucky. If FunctionStatement is used, it is not likely to be used on public websites.

I know it has been used on public web sites.

A major US defense company I once dealt with had an app that was Mozilla-only (due to security concerns in IE). It is possible that they successfully used a FunctionStatement. It seems that making FunctionStatement a syntax error could cause a problem in a Mozilla-only application, where as making FunctionStatement a standard would not cause problems (unless the problem was that the original code so badly confused):-

The ES3.1 proposal (now withdrawn, I believe) would make your example
below throw a runtime error, since the declaration of function a would
have only block scope and so would be unavailable after the if
statement completes.

if(IE || Opera) { function a(){ throw Error(); } // Error, but never reached. } else { function a(){} // No Error }

a();

Implementation of the FunctionStatement would cause the Error to be thrown when IE or Opera were true. How likely is such code to exist? Such code is arguably already broken and would seem to perform against the author's intention in IE.

That sounds to me to be:

  1. Somewhat useful
  2. Probably wouldn't cause much breakage (test).

I'm not sure what specifically you propose, but it would make me happy
if block-level function declarations could be standardized in a way
that tries to be compatible with existing practice. I realize this is
a challenge.

, Maciej

# Waldemar Horwat (16 years ago)

Mike Shaver wrote:

On Thu, Jul 10, 2008 at 1:48 AM, Allen Wirfs-Brock <Allen.Wirfs-Brock at microsoft.com> wrote:

FWIW, this sort of thing is a reason that I'm pretty concerned about ES3.1 getting into an advanced specification state without the benefit of any in-browser implementation.

You need to have an advance specification state before you can meaningfully test it in an implementation.

Sure, there's an interdependency, but it seems like you wouldn't want to propose something for inclusion into a short-turn spec like ES3.1 unless you'd seen it run somewhere relevant, no? Is there a document somewhere that tracks which ES3.1 features have been implemented in what prototype engine?

The key criterion here is whether you can come up with a language that makes sense. None of the existing behaviors make sense because they would make 'function' hoist differently from 'const' hoist differently from declaring other kinds of things in ES4, etc., with the only way of fixing it being introducing yet more ways of declaring things. The net result would be gratuitously hostile to everyone in the long term.

Waldemar
# Brendan Eich (16 years ago)

On Jul 10, 2008, at 6:01 PM, Waldemar Horwat wrote:

The key criterion here is whether you can come up with a language
that makes sense. None of the existing behaviors make sense
because they would make 'function' hoist differently from 'const'
hoist differently from declaring other kinds of things in ES4,
etc., with the only way of fixing it being introducing yet more
ways of declaring things. The net result would be gratuitously
hostile to everyone in the long term.

Agreed.

On the other hand, Maciej is probably right [1] that a non-trivial
amount of web content depends on intersection semantics today,
loading scripts under the default version (no type or else one of the
version-free javascript types). This is why I think opt-in versioning
is required to change the meaning of a function definition in a block.

/be

[1] bugs.webkit.org/show_bug.cgi?id=13790 is about a script at
starcraft2.com that once looked like this:

 if (ie||ns6)
 //var tipobj =  document.getElementById("dhtmltooltip");

 function ietruebody(){

Someone carelessly commented out the consequent, making the if (ie|| ns6) govern the definition of function ietruebody without bracing
that definition. In no proposed ES3.1 or ES4 would this be legal.
Anyway, the error has since been fixed, and last I looked, the page
did this:

 //if (ie||ns6)
 //var tipobj =  document.getElementById("dhtmltooltip");

 function ietruebody(){

See view-source:www.starcraft2.com/js/tooltip.js.

I'm interested in learning of more sites that seem to depend on
intersection semantics. Please post URLs to the lists.

# Brendan Eich (16 years ago)

On Jul 10, 2008, at 4:02 PM, Richard Cornford wrote:

A new specification probably should pin down which of these is
"correct". It should either reinforce the implication that the linkage is
intended to be long term or state the lifespan of the linkage (possibly saying
that it cannot be expected to hold past the lifespan of the execution
context for which the arguments object was created (thus categorizing longer term linkage as a possible non-standard extension)).

Hi Richard, thanks for bringing this to light. It's one of those
implementation secrets I try to forget, and actually manage to forget
sometimes. Indeed SpiderMonkey does not alias arguments[i] and the
activation (variable) object property for the corresponding formal
parameter after the underlying stack frame has been popped. This is
old as the hills, and even goes back to the original Netscape 2
("Mocha") runtime.

I would favour the latter

I do too, and not simply because that's what Mozilla's implementation
does (I don't know what Rhino does -- anyone?).

as the inconsistency in existing implementations makes it unlikely
that anyone is using this linkage outside of the functions whose calls
create the arguments objects, and there is nothing that could be done with
this linkage that could not be better (less obscurely) achieved using
closures.

ES4 is actually deprecating the arguments object. To do this with any
hope of being effective, we provide sweeter syntax without the
aliasing cruft: optional (default value given in the function
declaration) and rest parameters. Carrot, not stick.

I agree that specs should address this divergence of implementations
from the ES3 (ES1, IIRC) language. Would you be willing to file a bug
in the trac at bugs.ecmascript.org ? It would save me from
copying and pasting your fine message, and you would get email
notification of udpates to the ticket. Thanks,

# Brendan Eich (16 years ago)

On Jul 10, 2008, at 4:02 PM, Richard Cornford wrote:

Something like:-

fucntion getSomething(arg){ if(caseOneTest){ getSomething = function(x){ //actions appropriate for case one }; }else if(caseTwoTest){ getSomething = function(x){ //actions appropriate for case two }; }else{ getSomething = function(x){ //actions appropriate for other cases }; } return getSomething(arg); }

It is the ability to do this sort of thing that helps make
javascript so well suited to browser scripting.

Oliver Steele blogged about this kind of memoization a couple of
years ago:

osteele.com/archives/2006/04/javascript-memoization

although his examples did not show top-level function being replaced.
But it's a good point: strict mode wants to break useful (and used)
patterns that change the value of a property created by a defining form.

From Allen's list:

· Illegal for a function to have duplicately named formal
parameters · Illegal for a function to contain a top level function
declaration with a function name that is the same as a formal parameter. · Illegal to have multiple top level function declarations for
the same function name · Illegal to have a function declaration with the same name as
var declaration. · Illegal for a function to contain a var declaration with the
same name as a formal parameter. · Illegal to assign to a top-level function name.

I could see banning duplicate formal parameter names (I still have no
memory of why Shon from Microsoft wanted these standardized in ES1 --
possibly just because JScript already allowed them).

Shadowing a formal parameter with a nested function name also seems
likely to be a mistake.

Multiple top-level function definitions having the same name? That
must be allowed if the definitions are in separate scripts. In the
same script, it could be a mistake, or a fast patch of some kind.
Without #if 0 or nested comments (ES1-3 do not require them, I don't
know of any implementations that do them either) it's hard to hide
bulk code. Anyway, this seems less likely to be fruitful as a "good
taste" strict-mode check, more somewhat likely to bite back.

Within the same program, function vs. var name conflict is probably a
mistake to catch. I don't see it in web JS, but I'm not sure how
uncommon it is. Anyone have insights?

Function containing a var x and taking formal parameter x? That's
allowed and might be tolerated if the var has no initialiser, but if
the var has an initialiser then it is very likely to be a mistake.
Even when hacking and debugging it's rare to nullify an actual
argument by declaring a var and assigning to it in the var
declaration -- one would just assign without adding a var at the front.

# Richard Cornford (16 years ago)

Brendan Eich wrote:

On Jul 10, 2008, at 4:02 PM, Richard Cornford wrote:

Something like:-

fucntion getSomething(arg){ if(caseOneTest){ getSomething = function(x){ //actions appropriate for case one }; }else if(caseTwoTest){ getSomething = function(x){ //actions appropriate for case two }; }else{ getSomething = function(x){ //actions appropriate for other cases }; } return getSomething(arg); }

It is the ability to do this sort of thing that helps make javascript so well suited to browser scripting.

Oliver Steele blogged about this kind of memoization a couple of years ago:

osteele.com/archives/2006/04/javascript-memoization

although his examples did not show top-level function being replaced.

I was shown examples of doing this sort of thing back in 2002 shortly after I first started using javascript, so even if it has never become that common it certainly is not a new idea.

But it's a good point: strict mode wants to break useful (and used) patterns that change the value of a property created by a defining form.

I spend yesterday's commute to work thinking about this and came to the conclusion that I am completely wrong. If "Illegal to assign to a top-level function name" is interpreted as meaning (or re-worded to effetely say) that it is illegal to assign to a top-level name (activation/environment object property, or however that is best expressed) that was created_as_the_result_of_a_function_declaration (as opposed to a possible interpretation where it is illegal to assign to a top-level name that happens to refer to a function object) then there isn't really a problem.

There is no problem because if I want a self-reconfiguring function I can create one with a function expression. I.E.:-

var getSomething = function(arg){ if(caseOneTest){ getSomething = function(x){ //actions appropriate for case one }; }else if(caseTwoTest){ getSomething = function(x){ //actions appropriate for case two }; }else{ getSomething = function(x){ //actions appropriate for other cases }; } return getSomething(arg); };

  • and have the same facility for a negligible difference in effort. The minor change in execution, where a function declaration creates its function during variable instantiation and the above would create it at the execution of the assignment, isn't too problematic. It just means that the code that creates the function has to run before any code that attempts to use it (which is already true of much more common constructs such as the (so called) 'Crockford Module Pattern').

As this is "the cautious subset"/'strict' mode (or however it is to be known) we are talking about code that is yet to be written; so long as the facility remains the details of how it is achieved are not too important (at least so long as the useful existing possibilities don't become significantly more difficult to achieve).

From Allen's list:

· Illegal for a function to have duplicately named formal parameters · Illegal for a function to contain a top level function declaration with a function name that is the same as a formal parameter. · Illegal to have multiple top level function declarations for the same function name · Illegal to have a function declaration with the same name as var declaration. · Illegal for a function to contain a var declaration with the same name as a formal parameter.

I liked all of these from the outset. If I do any of these in the code I write then I have made a mistake, and being told as much ASP means that I can fix that mistake sooner rather than later.

· Illegal to assign to a top-level function name.

And in retrospect that one is OK too. If I don't what a top-level function replaced I can use a function declaration, and if I do I can assign a function expression to a variable; a little externally imposed formal discipline (and no harm in that).

I could see banning duplicate formal parameter names (I still have no memory of why Shon from Microsoft wanted these standardized in ES1 -- possibly just because JScript already allowed them).

I could not think of anything useful that could be done with multiple like-named formal parameters. The nearest I could get is if you wanted an object with a read-only - length - property of varying magnitude you could do something like:-

function makeFixedLengthObject(sizeOfLength){ function F(){} var c, ar = []; for(c = 0;c < sizeOfLength;++c){ ar[ar.length] = 'a'; } // The length of the array determines the value of the // length property of the constructed function object. F.prototype = new Function(ar.toString(), 'return'); // Hide the function methods so they will not be inherited // by the returned object. F.prototype.apply = undefined; F.prototype.call = undefined; F.prototype.toString = Object.prototype.toString; return new F(); /* The function object used as a prototype has a read only - length - property and the read only attribute is (effectively) inherited through the prototype chain so the returned object here has a read only - length - property as well. */ }

But I cannot envision a use for such an object, and it doesn't actually need like-named formal parameters because it would not be too hard to program the parameters to be a, aa, aaa, aaaa and so on.

Shadowing a formal parameter with a nested function name also seems likely to be a mistake.

Multiple top-level function definitions having the same name? That must be allowed if the definitions are in separate scripts.

I have seen an HTML template system where the top of the template defined a dummy function and the BODY onload attribute called that function unconditionally, with the idea that specific pages would insert or import a script that would declare a like-named replacement for the dummy function whenever they needed something executed onload.

In the same script, it could be a mistake, or a fast patch of some kind. Without #if 0 or nested comments (ES1-3 do not require them, I don't know of any implementations that do them either) it's hard to hide bulk code. Anyway, this seems less likely to be fruitful as a "good taste" strict-mode check, more somewhat likely to bite back.

The list does not include an "illegal to have multiple like-named variable declarations", so maybe something else that could be worked around by insisting that if there were to be more than one they each take the form of assigning a function expression to a declared variable? (as the "strict" mode implies an opt-in and new code)

Within the same program, function vs. var name conflict is probably a mistake to catch. I don't see it in web JS, but I'm not sure how uncommon it is. Anyone have insights?

My judgment would be very uncommon.

Function containing a var x and taking formal parameter x? That's allowed and might be tolerated if the var has no initialiser, but if the var has an initialiser then it is very likely to be a mistake.

I have seen a lot of event handlers take the form:-

el.onsomething = function(ev){ if(!ev){ var ev = window.event; } //code that used ev (the event object); };

  • with increasing frequency over the last couple of years. Presumably following an example from a book or somewhere. It is something between a misconception and a mistake (as in ES3 it is harmless), and I would have no problem with a 'strict' mode complaining about it.

Even when hacking and debugging it's rare to nullify an actual argument by declaring a var and assigning to it in the var declaration -- one would just assign without adding a var at the front.

You and I would, but unfortunately ...

# Sam Ruby (16 years ago)

Mike Shaver wrote:

On Thu, Jul 10, 2008 at 9:55 AM, Sam Ruby <rubys at intertwingly.net> wrote:

Library additions have less of a concern for interaction with real-world content, but the idea of inserting the code into something that will ultimately ship does appeal to me. If I were to do the work to put this code into SpiderMonkey(*), would you see it being included in some future release of Firefox?

  • Sam Ruby

(*) And it were to prove to be stable and doesn't break the web, and the function were to make some edition of ECMAScript, and yadda, yadda, yadda.

I can't see why not -- we'll certainly be looking to implement forthcoming editions of ECMAScript, and if decimal is a part of it then your code would certainly be helpful!

Did you say "if"? Grrr....

In any case, how about Firefox 3.1 then? :-)

code.intertwingly.net/public/hg/js-decimal

I have both instance (BigDecimal) and static (decNumber) methods implemented -- the later based on a suggestion by Allen, and will be rolled into the 3.1 spec post Oslo.

I still need to do some work on mapping exceptions, but in most cases exceptions aren't raised, for example Decimal.divide(1,0) produces Infinity. There also is some ES4 work to be done (e.g., infix operators and decimal constants).

I have 81,000+ tests ready to be ported over for decNumber, and can produce tests for the instance methods.

  • Sam Ruby
# Mike Shaver (16 years ago)

On Mon, Jul 14, 2008 at 11:08 AM, Sam Ruby <rubys at intertwingly.net> wrote:

Mike Shaver wrote:

I can't see why not -- we'll certainly be looking to implement forthcoming editions of ECMAScript, and if decimal is a part of it then your code would certainly be helpful!

Did you say "if"? Grrr....

Yes? I didn't think that ES3.1 or ES4 had committed to decimal, and in what form. Things are still being cut from both, last I checked; I meant no offense.

In any case, how about Firefox 3.1 then? :-)

Not really the forum for product-delivery discussions, but I think it would be reasonable to propose. Worth filing and nominating, certainly.

I have 81,000+ tests ready to be ported over for decNumber, and can produce tests for the instance methods.

Excellent!

Mike