ES3 Specification oddness.

# Mark S. Miller (17 years ago)

While making an editing pass over the ES3.1 draft spec, I came across the following oddness inherited from the ES3 spec:

8.6.2.2 [[Put]] (P, V) When the [[Put]] method of O is called with property P and value V, the following steps are taken: 1. Call the [[CanPut]] method of O with name P. 2. If Result(1) is false, return. ....

8.6.2.3 [[CanPut]] (P) The [[CanPut]] method is used only by the [[Put]] method. When the [[CanPut]] method of O is called with property P, the following steps are taken: 1. If O doesn't have a property with name P, go to step 4. 2. If the property has the ReadOnly attribute, return false. 3. Return true. 4. If the [[Prototype]] of O is null, return true. 5. Call the [[CanPut]] method of [[Prototype]] of O with property name P. 6. Return Result(5).

As I read this spec, if object B inherits from object A, A has a ReadOnly 'foo' property, and B does not have its own 'foo' property, then this spec says that

B.foo = ...

should fail rather than define an own 'foo' property on B. This seems to imply that ReadOnly implies non-overrideable. (Curiously, Java used the keyword "final" for both concepts, but that's just a coincidence. In Java, it means one or the other depending on whether it applies to a field or a method.)

Is this intended or a mistake? Do JavaScript implementations obey this peculiar behavior? Do programs depend on it?

# Brendan Eich (17 years ago)

On May 18, 2008, at 8:10 PM, Mark S. Miller wrote:

Is this intended or a mistake?

It's intended, it goes back to ES1 drafts written by the Microsoft
lead with agreement from all participating in TG1 back then (1996-1997).

Do JavaScript implementations obey this peculiar behavior?

Yes:

js> function f(){}

js> f.prototype = Date

function Date() { [native code] } js> o = new f

Function.prototype.toString called on incompatible object js> o.prototype = 42

42 js> o.prototype

Invalid Date

(SpiderMonkey shell, same as in Firefox.)

Rhino follows the spec, and I'm pretty sure (can't test, no PCs at
home) IE does too. Safari does not, looks like a JavaScriptCore bug.
IIRC, Opera does now, having recently fixed a long-standing bug.

Do programs depend on it?

I don't know of any, but we've been down this road before. Without a
widely distributed browser trying out a change from the standard (de- facto or de-jure) at beta scale or better, we can't prove a negative.
We know from past attempts of similar changes that the odds are not
good. It's not encouraging if IE and Mozilla-based engines agree with
ES1-3 here, as IE and (long ago) the Mozilla progenitor
implementation in Netscape browsers set the de-facto standard.

There's no point borrowing trouble here, IMHO. I agree we want to
separate read-only from no-override-allowed, but in new, compatible- because-opt-in territory. Hence ES4 classes with const and final as
separate attributes.

# Steven Mascaro (17 years ago)

The use of Date makes things look odd, but I assume the spec means something like the following:*

js> function f(){}

js> f.prototype = {const prop1: 1, prop2: 2}

js> o = new f

js> o.prop1 = 42

42 js> o.prop1

1

which is the behaviour I'd expect.

  • I can't find the notation for const's in object literals.
# Brendan Eich (17 years ago)

On May 19, 2008, at 12:56 AM, Steven Mascaro wrote:

The use of Date makes things look odd, but I assume the spec means something like the following:*

js> function f(){} js> f.prototype = {const prop1: 1, prop2: 2} js> o = new f js> o.prop1 = 42 42 js> o.prop1 1

which is the behaviour I'd expect.

  • I can't find the notation for const's in object literals.

You're using the ES4 syntax; there's no const in ES3.

Yeah, I picked Date but any standard constructor will do (because
standard constructors have DontDelete + ReadOnly attributes for
their .prototype properties). So you could s/Date/Object/g, but Date
suffices and its toString is less anonymous (i.e., not "[object
Object]").

Other suitable DontDelete + ReadOnly properties than the standard
constructors' prototype properties in ES3 include String length,
Number.MAX_VALUE, etc.

Recollecting more from ES1 days, we did not think about const per se,
but we did want to prevent ReadOnly properties from being overridden
in delegates where related properties and methods that depended on
the ReadOnly value were not overridden, therefore found in a
prototype. Integrity again.