Comments on April ES5 final draft standard tc39-2009-025

# Mark S. Miller (16 years ago)

4.2.1 Objects

... constructors which create objects by executing code that allocates storage for the objects and initializes ...

Javascript code does not express explicit allocation, so I suggest deleting "allocates storage for the objects and".

5.1.7 Grammar Notation

For convenience, the set can also be written as a nonterminal, in which case it represents the set of all terminals to which that nonterminal could expand.

Since a nonterminal can expand into a sequence of terminals, this can be misread as including any terminal in any possible expansion, even if it can't be an initial terminal. In practice, I believe this shorthand is only used for one terminal deep nonterminals. Not sure what is the best way to clarify. Perhaps simply "... set of all initial terminals to ...".

7.1 Unicode Format Control Characters

The format control characters may be used in identifiers, within comments, and within string literals and

regular expression literals.

I think someone else already pointed out that "in identifiers" should be deleted. Once it is, why not simply include format control characters in whitespace?

7.5.1 Reserved Words

Reserved words cannot be used as identifiers.

Suggest "Identifiers" and using a distinguished font, in order to emphasize that we're talking about the Identifier production. This comes up several other places: 7.5.2, 10.2.1.2,

7.5.3 Future Reserved Words

NOTE The identifiers 'let‘, and 'yield‘ may be used in a future version of this standard.

At the last meeting, we had agreed to prohibit these in strict code, effectively reserving them, but I cannot find any text stating this prohibition.

7.6 Identifiers

Identifiers are interpreted according to the grammar given in the "Identifiers" section of chapter 5 of the

Unicode standard

Suggest:

7.6 IdentifierNames

IdentifierNames are interpreted according to the grammar given in the "Identifiers" section of chapter 5 of the Unicode standard

(in other words, conforming ECMAScript implementations are only required to do bitwise comparison on identifiers)

"only required" sounds like they could do more if they like. How about "required to only do..."?

Note at end of 7.8.4 String Literals

Font change in middle of word "sequence".

7.8.5 Regular Expression Literals

An implementation may extend the regular expression constructor's grammar, but it should not extend the RegularExpressionBody and RegularExpressionFlags productions or the productions used by these productions.

Should "should" be "must"?

8.6.1 Property Attributes, Table 1

[[Writable]] Boolean If false, attempts by ECMAScript code to change the property‘s [[Value]] attribute will not succeed.

Not quite true, since a configurable non-writable property can still be changed by defineProperty. How about

"to change the property's [[Value]] by assignment will not succeed."

[[Configurable]] Boolean If false, attempts to delete the property, change the property to be an accessor property, or change its attributes (other than [[Value]]) will fail.

Not quite true, since a writable non-configurable property can still be made non-writable.

8.6.2 Object Internal Properties and Methods, Table 4

Doesn't the signature of [[DefineOwnProperty]] need a return type of "→ Boolean"? Likewise for the title of 8.12.10

8.6.2 Object Internal Properties and Methods, Table 5

[[Call]] SpecOp(a List of any) → any or Reference

should this be "SpecOp(thisArg, a List of any) → any or Reference"?

Executes code associated with the object. Invoked via a function call expression. The arguments to the SpecOp are the arguments passed to the function call expression. Objects that implement this internal method are functions. Only functions that are host objects may return Reference values.

Conflicts with definitions elsewhere of "function". Based on previous conversations, I think this should be

"Objects that implement this internal method are callables. Only callables that are host objects may return Reference values."

[[HasInstance]] SpecOp(any) → Boolean Returns a Boolean value indicating whether the argument is an Object that delegates behaviour to this object. Of the standard built-in ECMAScript objects, only Objects that are instances of the standard built-in constructor Function implement [[HasInstance]].

The first sentence is wrong. [[HasInstance]] tests whether the argument delegates to this object's ".prototype".

"built-in" above should probably be "native", since it applies to all objects whose behavior is defined by this spec (i.e., not host objects). "built-in" objects are specifically those that exist before execution begins, which is not the distinction you intend. This problem comes up several places, such as the next 3 rows of table 5 , the [[Match]] row, and the first paragraph of 8.7.

However, the above paragraph is still wrong. Function.prototype is not an instance of the constructor Function, though presumably it does implement [[HasInstance]]. Also, Object.create(Function.prototype) would create an instance of the constructor Function that doesn't implement [[HasInstance]]. Perhaps the distinction is: Functions are objects whose [[Class]] is "Function".

8.7 The Reference Specification Type

The base value is either null, an Object, a Boolean, a String, a Number, or an environment record (10.2.1). A base value of null indicates that the reference could not be resolved to a binding.

This use of null implies that calling a strict function as a function will bind its this to "null". This is inconsistent with previous decisions as well as, for example, Annex D "called as a function, undefined as passed as the this value." This problem reappears several places: 10.2.1.1.7, 10.2.1.2.5, step 7 of 11.2.3,

If all of these were simply changed from "null" to "undefined", I believe the only observable difference would be to correct the "this" binding of strict functions called as functions.

Separately, it s not clear what the term "binding" means above. Likewise "binding values" in the table in 10.2.1.

Note at end of 8.7.2 PutValue (V, W)

or is in violation of a Throw conditioned error check

I have no idea what this means.

8.12.9 [[DefaultValue]] (hint)

When the [[DefaultValue]] internal method of O is called with hint String,

Throughout the spec, when speaking of hints, String and Number appear in normal font and without quotes. However, presumably, these are actually the strings "String" and "Number". To clarify, these should have quotes and perhaps be in code font.

9.2 ToPrimitive

Should this title include the signature? Perhaps "ToPrimitive(value, PreferredType) → primitive | undefined | null

9.4 ToInteger

  1. Let number be the result of calling ToNumber on the input argument. ...
  2. Return the result of computing sign(number) * floor(abs(number)).

I think this is always representable, but I'm not sure so I thought I'd ask.

10.2.2.3 NewObjectEnvironmentRecord(O, E)

Why not make ProvideThis another parameter of NewObjectEnvironmentRecord, rather than setting it after creation? I think it would make things simpler and clearer.

10.4.2 Eval Code

  1. If there is no calling context or if the eval code is not being evaluated by a direct call

"If there is no calling context or" is unnecessary, since any such circumstance cannot be a direct call.

Note at end of 10.5 Arguments Object.

The "caller" property has a more specific meaning for non-strict mode functions and a "callee" property has historically been provided as an implementation-defined extension by some ECMAScript implementations.

"caller" and "callee" are switched here. "callee" is the specified one.

11.1.1 The this Keyword

The this keyword evaluates to the value of the ThisBind of the current execution context.

ThisBinding?

11.4.2 The void Operator

  1. Call GetValue(expr).
  2. Return undefined.

It is obscure why GetValue is being called when its value is ignore. Perhaps a note to clarify? Also 11.14.

11.5 Multiplicative Operators

  1. Let left be the result of evaluating MultiplicativeExpression.
  2. Let leftValue be GetValue(left).
  3. Let right be the result of evaluating MultiplicativeExpression UnaryExpression.
  4. Let rightValue be GetValue(right).
  5. Let leftNum be ToNumber(leftValue).

The extra "MultiplicativeExpression" in step 3 should be deleted.

Shouldn't step 5 occur between steps 2 and 3?

11.5.1 Applying the * Operator

If the magnitude is too large to represent, the result is then an infinity of appropriate sign. If the magnitude is too small to represent, the result is then a zero of appropriate sign. The ECMAScript language requires support of gradual underflow as defined by IEEE 754.

This boilerplate code occurs several places: 11.5.2, 11.6.3. Can't it simply be replaced with ToNumber, where this conversion is already covered?

11.8.7 The in operator

  1. If Type(rval) is not Object, throw a TypeError exception.

This seems less useful than either doing a ToObject or just returning false. I prefer doing ToObject.

11.13.1 Simple Assignment ( = )

The LeftHandSide also may not be a reference to a property with the attribute value {[[Writable]]:false} nor to a non-existent property of an object whose [[Extensible]] internal property has the value false.

Nor to an accessor property with attribute value {[[Setter]]: undefined}. Likewise in Annex C.

12 Statements

The label set of an IterationStatement or a SwitchStatement initially contains the single element empty. The label set of any other statement is initially empty.

Even though these two conflicting uses of "empty" are distinguished by font, it is still confusing. Also, what kind of value is "the single element empty"? For example, could one read the spec as implying that

empty: { break; }

is legal, since

empty: { break empty; }

is legal, and "empty" is the implicit break label of the former. See also the "empty" at end of 12.12.

12.12 Labelled Statements

If the result of evaluating Statement is (break, V, L) where L is equal to Identifier, the production results in (normal, V, empty).

or "(continue, V, L)"?

13.1 Strict Mode Restrictions

... if the Identifier "eval" appears within a FormalParameterList of a strict mode

FunctionDeclaration or FunctionExpression.

... if the Identifier "eval" appears as the Identifier of a strict mode FunctionDeclaration.

I don't remember for sure, but didn't we decide to prohibit bindings of "arguments" in strict code, just as we correctly do for "eval"?

13.2.3 The [[ThrowTypeError]] Function Object

  1. Set the [[Call]] internal property of F as described in 13.2.1.
  2. Set the [[Scope]] internal property of F to the Global Environment.
  3. Let names be a List containing, in left to right textual order, the strings corresponding to the identifiers of FormalParameterList.

The inclusion of steps 4, 5, and 6 here look like a copy paste error.

14 Program

The production SourceElement : FunctionDeclaration is evaluated as follows:

  1. Return (normal, empty, empty).

This implies that

eval("3; function foo(){}")

should return undefined. On FF 3.0.9 it returns 3, which I had understood was correct. I also don't think this is an intended change from ES3 to ES5.

15 Standard Built-in ECMAScript Objects

Unless otherwise specified in the description of a particular function, if a function or constructor described in this section is given more arguments than the function is specified to allow, the behaviour of the function or constructor is undefined.

Is this what we decided on, or did we decide that "unless otherwise specified" extra arguments are ignored?

Also, what's the difference between "undefined" behavior and "implementation-dependent" behavior, as is used elsewhere in the spec?

Every built-in prototype object has the Object prototype object, which is the initial value of the expression Object.prototype (15.2.4), as the value of its [[Prototype]] internal property, except the Object prototype object itself.

Isn't, for example, the value of RangeError.prototype's [[Prototype]] property Error.prototype and not Object.prototype?

15.1 The Global Object

The values of the [[Prototype]] and [[Class]] internal properties of the global object are implementation-dependent.

I suspect that we're currently confused about whether the global object should be considered a native or host object. A browser Window object is clearly a host object. Weird.

15.1.2.1 eval (x)

  1. Let prog be the ECMAScript code that is the result of parsing x as a Program. If the parse fails, throw a SyntaxError exception (but see also clause 16).

Chapter 16?

15.1.2.4 isNaN (number)

Returns true if the argument is NaN, and otherwise returns false.

  1. If ToNumber(number) is NaN, return true.
  2. Otherwise, return false.

I got bit by believing the summary line. Instead, because of the ToNumber in the algorithm, isNaN("") returns true. Should say "Returns true if the arguments coerces to NaN..."

Also add Note to effect that a reliable test of whether x is a NaN is "x !== x".

15.1.3 URI Handling Function Properties

uriReserved ::: one of ; / ? : @ & = + $ ,

What about "#"?

15.2.3.4 Object.getOwnPropertyNames ( O )

Should add a note that (unlike keys) the result includes non-enumerable own property names.

15.2.3.5 Object.create ( O [, Properties] )

  1. If Type(O) is not Object throw a TypeError exception.

Probably too radical a change to consider at this late date, but should we have allowed O to be null?

15.2.3.8 Object.seal ( O ) and 15.2.3.9 Object.freeze ( O )

Ends with text explaining failure atomicity of these operations. However, I think neither of these operations can fail.

15.2.3.11 Object.isSealed ( O )

  1. If the [[Extensible]] internal property of O is false, then return true.
  2. Otherwise, return false.

15.2.3.12 Object.isFrozen ( O )

  1. If the [[Extensible]] internal property of O is true, then return false.
  2. Otherwise, return true.

The first steps 3 and 4 means the same thing as the second steps 3 and 4. Both are correct. They should use the same formulation.

15.2.4 Properties of the Object Prototype Object

and the value of the [[Extensible]] internal property is true.

Should be "the initial value..."

15.3.3 Properties of the Function Constructor

The Function constructor has properties named "caller" and "arguments" whose initial value is null. These properties have attributes: attribute {[[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false}. An ECMAScript implementation must not associate any implementation specific behaviour with access of these properties.

This is inconsistent with 13.2 step 16, which defines these as accessors using the thrower to throw. 13.2 is correct. 15.3.4.5 steps 18 and 19, the last paragraph of 15.3.5, and Annex C make the same mistake.

15.3.4.3 step 6

"Len" should be "Let".

15.3.5.3 [[HasInstance]] (V)

does not apply to functions created by bind.

15.4.2.2 new Array (len)

If the argument len is a Number and ToUint32(len) is equal to len, then the length property of the newly constructed object is set to ToUint32(len).

Since they're equal, the end of the sentence can be simplified from "ToUint32(len)" to "len".

15.4.4.16 Array.prototype.every ( callbackfn [ , thisArg ] )

every acts like the "for all" quantifier in mathematics. In particular, for an empty array, it returns true.

I like this. But

15.4.4.17 Array.prototype.some ( callbackfn [ , thisArg ] )

has no such sentence. How about

'some acts like the "exists" quantifier in mathematics. In particular, for an empty array, it returns false."

15.4.5.1 (Array's) [[DefineOwnProperty]] ( P, Desc, Throw )

step 3.a.vi.2 Let cantDelete be the result of calling the [[Delete]] internal method of A passing ToString(oldLen) and false as arguments.

together with

15.4.5.2 length

The length property of this Array object is a data property whose value is always numerically greater than the name of every deletable property whose name is an array index.

I'm not sure what's being said here. How do non-deletable indexes affect setting length?

15.5.5.2 [[GetOwnProperty]] ( P )

  1. Return a Property Descriptor { [[Value]]: resultStr, [[Enumerable]]: true, [[Writable]]: false, [[Configurable]]: false }

Since these numeric pseudo-properties are not enumerated by for-in loops, we should describe them as non-enumerable.

15.7.4 Properties of the Number Prototype Object

if Type(this value) is Number

typo. Should be "if Type(value) is Number".

15.8.2.14 (Math's) random ( )

Should add a note recommending that implementations provide high enough quality randomness as to make it infeasible to infer how many times random() was called between two calls to random(). If that is unacceptable, then should add the opposite note warning that programs may so infer, creating a covert channel hazard.

15.11.5 Properties of Error Instances

Error instances have no special properties beyond those inherited from the Error prototype object.

Shouldn't the "name" and "message" properties of 15.11.4.(2 & 3) instead be properties on Error instances? Likewise with 15.11.7.11.

Annex C

missing close paren after "Function.prototype.call".

When a delete operator occurs within strict mode code, a ReferenceException is thrown if its UnaryExpression is a direct reference to a variable, function argument, or function name.

Shouldn't this be an early error?

JSON to be covered separately.

# Mark S. Miller (16 years ago)

2009/4/25 Mark S. Miller <erights at google.com>:

JSON to be covered separately.

15.5.4.21 String.prototype.toJSON ( key ) 15.6.4.4 Boolean.prototype.toJSON ( key ) 15.7.4.8 Number.prototype.toJSON ( key )

All three of these use the same boilerplate to a) typically unwrap a wrapped primitive, and b) in all cases ensure a primitive is returned. This seems largely redundant with ToPrimitive. How about for all of these just saying

1. Return the result of calling ToPrimitive on the this value.

Alternatively, all these are already almost redundant with logic within the JSON.stringify algorithm. But slightly repairing that logic (see below), we can simply remove these three methods; simplifying the spec.

15.12.1.2 The JSON Syntactic Grammar

defines a valid JSON text in terms of tokens from defined by the

delete "from"

15.12.2 parse ( text [ , reviver ] )

The JSON format is a restricted form of ECMAScript literal.

Not quite. \u2028 and \u2029 can appear in a JSONString unescaped. But ES5 considers these to be newline characters, and so they can only appear in ES5 literal strings if escaped. We need a note to that effect.

In abstract Walk operation, step 2, what's the purpose of the IsCallable test here? I think this test should be deleted.

2.a.iii.2 Let newElement be the result of calling the [[Put]] internal method ...

This binding of newElement is never used. Which is a good thing because [[Put]] doesn't return anything anyway. Also, it is not necessarily the case that this [[Put]] will succeed. Change to

Call the [[ThrowingPut]] internal method ... and true.

2.b.i. ... Object.key ...

Should be Object.keys. Likewise in step 6.a of JO.

15.12.3 stringify ( value [ , replacer [ , space ] ] )

The value parameter is a JavaScript value is usually an object or array, ...

Insert "that" between "value" and "is".

Step 7 of Str

The unwrapping here of Strings and Numbers is redundant with that in their toJSON methods as mentioned above. However, Boolean is left out here. I think it is better to have the unwrapping of primitive wrappers here, with Boolean repaired, and to remove the redundant toJSON methods on Number.prototype, String.prototype, and Boolean.prototype.

JO and JA refer to the abstract operation "str". Should be "Str".

JA step 10.b.iii. uses "{" and "}". Should be "[" and "]".

Several of the issues I've raised in this and my earlier message were first noticed by other Googlers and raised internally.