archives

« Bugzilla Issues Index

#4243 — Function name in strict functions


All existing engines treat the function name of a strict function as strict. However, the spec seems to imply that only the formal parameters and the function body is strict.

All existing engines treat this as error:

// sloppy code
function static() {
'use strict';
}

But the spec seems to imply that that is valid?


Here's the reading of the spec that prompted my reports against SpiderMonkey
[1] and V8 [2].

From the ES5 spec:

> The following tokens are also considered to be FutureReservedWords when they
> occur within strict mode code (see 10.1.1). [3]

...which defines "strict mode code":

> Function code that is part of a FunctionDeclaration, FunctionExpression, or
> accessor PropertyAssignment is strict function code if its
> FunctionDeclaration, FunctionExpression, or PropertyAssignment is contained
> in strict mode code or if the function code begins with a Directive Prologue
> that contains a Use Strict Directive. [4]

...and "function code":

> 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 nested FunctionBody. 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. [5]

So since the BindingIdentifier is not considered part of the function code, it
should not be interpreted according to the strictness of the function itself.
This interpretation also holds in ECMAScript 6 [6].

[1] https://bugzilla.mozilla.org/show_bug.cgi?id=1145191
[2] https://code.google.com/p/v8/issues/detail?id=3975
[3] http://es5.github.io/#x11
[4] http://es5.github.io/#x10.1.1
[5] http://es5.github.io/#function-code
[6] Relevant definitions in the ES6 spec draft:
- https://people.mozilla.org/~jorendorff/es6-draft.html#sec-identifiers-static-semantics-early-errors
- https://people.mozilla.org/~jorendorff/es6-draft.html#sec-strict-mode-code
- https://people.mozilla.org/~jorendorff/es6-draft.html#sec-types-of-source-code
- https://people.mozilla.org/~jorendorff/es6-draft.html#sec-function-definitions


As to whether this is a bug in the spec itself: the spec seems intuitive (and
the current implementation seems unintuitive) because of the effect function
declarations have on the environment record.

function static() {
'use strict';
}

From the perspective of the identifiers themselves (i.e. disregarding
hoisting), this is similar to:

var static;
static = function() {
'use strict';
};

In both cases, the identifier `static` is used to create an entry in the outer
(sloppy) environment record. The strictness of the function has no effect here.
Contrast this with function expressions, where the spec and current
implementations are in alignment. This example generates a SyntaxError:

(function static() {
'use strict';
});

...and this behavior maps to the version that does not use an identifier in the
function expression:

var __tmp = function() {
'use strict';
var static = __tmp;
};


mike: I think your explanation makes total sense.

Maybe it is safe to change the existing engines?


This seems unlikely to be problematic. Let's see if we can make the change in our engines before we push for a spec change.


That said, according to #174 (https://bugs.ecmascript.org/show_bug.cgi?id=174) seems to have decided that browsers' current behavior is what the spec should reflect. I wonder why this bug was not resolved? Is that no longer the intention?


(In reply to Brian Terlson from comment #5)
> That said, according to #174
> (https://bugs.ecmascript.org/show_bug.cgi?id=174) seems to have decided that
> browsers' current behavior is what the spec should reflect. I wonder why
> this bug was not resolved? Is that no longer the intention?

A slippery slope ;)

If this argument is used for all cases in which browsers/runtimes/etc have implemented the spec incorrectly, then even


(In reply to Rick Waldron from comment #6)
> (In reply to Brian Terlson from comment #5)
> > That said, according to #174
> > (https://bugs.ecmascript.org/show_bug.cgi?id=174) seems to have decided that
> > browsers' current behavior is what the spec should reflect. I wonder why
> > this bug was not resolved? Is that no longer the intention?
>
> A slippery slope ;)
>
> If this argument is used for all cases in which browsers/runtimes/etc have
> implemented the spec incorrectly, then even

Please ignore this idiotic non-sense.

I had typed this before fully considering the argument being made and how it applies to anything we're discussing here. At some point, I scrolled to the top of the bug and then I left the page entirely. After reading the linked bug and cc'ing myself there, I returned to this bug's tab and clicked "save changes" at the top of the page to cc myself on this as well. Of course, I completely forgot the Bugzilla (being the crappiest pile of garbage ever cobbled together) treats the entire page as the same form and as a result of hitting "save changes" (in a completely different region of the page), I also accidentally posted comments that no longer reflected my current thoughts on the subject.

Sorry about that.


While I stand by the argument in made in Bug #174 for that point in time, I also think that Mike has a strong argument that for FunctionDeclaration the binding identifier is part of the code of the surrounding scope and hence the strictness of that scope should apply to it.

Here is another case, that I think adds some insight:

"don't use strict";
var foo = {bar: "baz"};
var obj = {
[()=>{with (foo) return bar}()] () {
"use strict";
//method body...
},
strict() {
"use strict"
//method body
}
}

The computed property name is part of the MethodDefinition but it is computing a property name for a sloppy mode object literal. It doesn't seem right that strict mode be applied to the property name computation in the first method. But if that is the case, then for consistency sake it also should not apply to the second method definition.

I don't think we can arrive a single consistently apply rule. Instead, here is an enumeration of what I think the rules should be for the various cases (in all cases we are talking about a strict mode function in sloppy mode code):

1) BindingIdentifier of a FunctionDeclaration/GeneratorDeclaraton: sloppy mode because the identifier is only bound in the sloppy mode scope
2) BindingIdentifier of a FunctionExpression/GeneratorExpression: strict because the identifier is only bound in an inner scope of the function
3) BindingIdentifier of a ClassDeclaration: strict because the identifier in addition to being bound in the sloppy mode scope is also bound in an inner scope of the class body and the a class body is always strict.
4) BindingIdentifer of a ClassExpression: strict because the identifier is bound in an inner scope of the class body
5) PropertyName of a MethodDefinition in a sloppy mode ObjectLiteral: sloppy mode
6) PropertyName of a MethodDefinition in a ClassBody: strict because all parts of a class body are strict


Those rules looks good to me.


Closely related, but more serious: bug 4426.