TC39 meeting Wed 5/23/2012

# Rick Waldron (12 years ago)

Override Mistake (Allen Wirfs-Brock, Mark Miller)

AWB:

  • The correct people are not here for this discussion, defer to next meeting

4.14, Unicode (Norbert Lindenderg)

NL:

norbertlindenberg.com/2012/05/ecmascript-supplementary-characters/full-unicode-in-ecmascript.pdf

AWB:

  • Concretely, should supplementary characters gain coverage in the currently developing draft.

MM:

  • Mention of spec modularity

AWB:

  • Implication for strings etc.

NL, LH, MM:

  • Any objections? No.

AWB:

  • Canonicalize everything to full unicode grammar
  • Don't think this will change implementation rules

LH:

  • Asks for confirmation

NL, AWB:

  • Confirms no difference.

Resolution: Promoted unanimously to harmony status

4.11, Daylight Savings (Luke Hoban)

Move to remove/reword:

15.9.1.8 "An implementation of ECMAScript is expected to determine the

daylight saving time algorithm."

AWB:

  • There needs to be a specification of some sort, as other aspects of the standard rely on this.

more discussion.

Some locales do change

LH:

  • Operating systems and browser do have disagreements

AWB:

  • Either NL or LH can draft replacement text for 15.9.1.6 and 15.9.1.8

more discussion.

Resolution: Remove the spec text, new additions will be considered as new proposal

Not errata.

4.10 Object.observe (Rafeal Weinstein)

Rafeal Weinstein:

  • Introduction to proposal

See: strawman:observe

MM:

  • In favor of spec'ing an event loop

Alex Russel:

  • This doesn't actually change anything in the spec today

MM:

  • Run program code to completion, etc.

LH:

  • last execution context

AWB:

  • Currently no concept of "last execution context"

YK:

  • It's implicit

LH:

  • Agrees, needs to be specified

OH:

  • What happens if the object is mutated before the callback delivers?

Explanation of side-channel communication of objects.

YK:

  • Explains the idea, needs of observing an entire object.

Discussion about object safety.

Discussion about frozen object safety.

Discussion about non-configurable, non-writable property change delivery.

MM:

  • Will adding the text "Any non-frozen" change the operational behaviour?

YK:

  • No, frozen objects should probably not deliver a property changes

Erik Arvidsson:

  • Deferring to MM

MM:

  • Observe proxy?

EA:

  • Non-issue, the traps only the final property

LH:

  • More explanation of Proxy property trap behaviour

AWB:

  • There is too much going on at low level with this proposal

Discussion about importance

BE:

  • Important does not mean "it's in"

RWeinstein:

  • What if this didn't apply to Proxy?

BE:

  • The DOM…

More discussion regarding security, naivety of proposal

BE:

  • Let's have Tom Van-Cutsem take a look at this and iron out

RWeinstein:

  • Asking for blessing to prototype in v8: approved.

Resolution: Needs more exploration

Spec Issues (Allen Wirfs-Brock)

Object.isObject

Misses the mark on actual needs.

BE:

  • Possibly, Object.typeOf()?

Doug Crockford:

  • Need to re-address this for reality.

YK:

  • Will write strawman for review at next meeting.

Resolution: Consensus to remove from draft

super

LH:

  • This may be too confusing for the common user

AWB:

  • Asserts that super is defined correctly for classes (explanation)

Should super be allowed in all function forms or restricted to classes?

Resolution: Defer super outside of classes

Concise Methods

Resolution: In favor

Concise Body

Resolution: Only for ArrowFunction

Property Assignment Shorthand

eg. function point(x, y) { return { x, y }; }

{ x: x, y: y }

This is too unclear w/r to destructuring: both, or nothing. Plenty of opposition based on clarity.

Resolution: Nothing, no change.

Triangle

Is capable of giving up private names

If people have proto they will not use <|.

MM:

  • From a security perspective, I'd like to move proto out of annex B and into normative body

BE:

  • If MS puts proto in IE, then it becomes defacto standard and we might as well put it in the standard.
  1. proto
  2. grawlix

Resolution: Indefinite postpone

Moustache

o.{ p: v }

BE:

  • Propose that moustache is kept, but still consider Object.extend

MM:

  • Would like to consider both moustache and Object.extend

How about… both? = assign : define

ie.

o.{ p1: "to define", p2 = "to assign" };

Positions:

Just Define Just Assign Both Define and Assign Alone Applied to object literals

Resolution: Return to strawman for revision, needs own wiki page.

Computed Keys

Erik Arvidsson:

  • Today, properties are static and knowable, computed keys are not knowable.

Resolution: Deferred.

SealedObjectLiteral

See: ecmascript#362

Resolution: Postponed until ES7.

String.prototype.toArray

Resolution: Removal from draft.

Weak Refs

Yehuda Katz:

  • Use case: observers

Resolution: Continued, due to lack of time.

Value Objects

Brendan demos, explanation of the implementation and operator overloading

# Brendan Eich (12 years ago)

Rick, thanks for taking these. I'll try to add a bit of explanation where it looks like "you had to be there" ;-).

/be

Rick Waldron wrote:

4.10 Object.observe (Rafeal Weinstein)

Rafeal Weinstein:

  • Introduction to proposal

See: strawman:observe

MM:

  • In favor of spec'ing an event loop

BE: let's subset the parts of Hixie's HTML5 spec that we need, and no more (and reference that spec so it's likelier we keep the subset relation).

AWB:

  • There is too much going on at low level with this proposal

Allen's point was that all of the strawman champions and Allen, the spec editor, and experts and interested folks (Tom Van Cutsem, people on es-discuss) all need to digest the non-local effects of the local but low-level changes in the strawman.

I said this, and also offered that we would prototype in SpiderMonkey alongside V8.

RWeinstein:

  • Asking for blessing to prototype in v8: approved.

I emphasized that all strawman not moved to deferred: namespace in the wiki (and there's a curation process here, which can fail sometimes) are fair game for prototyping.

Property Assignment Shorthand

Rather, "Object Literal" or "Property Definition" (in ES3, PropertyAssignment) shorthand.

eg. function point(x, y) { return { x, y }; }

{ x: x, y: y }

This is too unclear w/r to destructuring: both, or nothing. Plenty of opposition based on clarity.

Resolution: Nothing, no change.

That is, we keep the shorthand for structuring as well as for destructuring where it is clearly useful.

LH observed that the 90%+ by frequency use-case for destructuring wants the shorthand, whereas for structuring (making an object via an object literal expression) it's more like 10% or 1%. BE agrees but BE and MM at least want duality consistency: shorthand for both literals and patterns.

That's where we left ES6.

I personally think the "n00bs will see the new shorthand and artificiailly declare variables of the same name as the property just to use the shorthand" worry as an undemonstrated speculation, and too fearful. We need user-testing evidence of this!

EA raised the other interpretation of {x,y} in an expression, as a WebIDL-ish enum equivalent to {x: "x", y: "y"} -- for making string manifest constants named by the string contents -- but this is a different semantics, and rarer yet than {x,y} to make a point from x and y bindings.

AR mentioned future-hostility to set notation in JS. BE ack'ed that, figures it is un-possible given object literals being wrapped in curlies anyway.

Triangle

Is capable of giving up private names

If people have proto they will not use <|.

MM:

  • From a security perspective, I'd like to move proto out of annex B and into normative body

BE:

  • If MS puts proto in IE, then it becomes defacto standard and we might as well put it in the standard.
  1. proto
  2. grawlix

Resolution: Indefinite postpone\

I.e., we defer/cancel triangle and go with normative mandatory proto. W00t! Kidding, mostly, but I perpetrated it, it is in all browsers but IE, and IE feels the heat on mobile (thank you Thomas Fuchs!). So proto is the winner already, we're just trying to forestall the inevitable.

Moustache

o.{ p: v }

BE:

  • Propose that moustache is kept, but still consider Object.extend

MM:

  • Would like to consider both moustache and Object.extend

How about… both? = assign : define

ie.

o.{ p1: "to define", p2 = "to assign" };

Further choice: allow = instead of : in object literals too, not just in mustache-literals!

Positions:

Just Define Just Assign Both Define and Assign Alone Applied to object literals

Ah, you got that one. Thanks.

OH worried that the JSON theft attack (a global setter targeting well-known id in top-level JSON blob) would work, but this requires both = instead of : in the JSON blob, and the wrong MIME type for loading JSON as a <script>.

Resolution: Return to strawman for revision, needs own wiki page.

I still want mustache. My advice was to copy and lightly mutate the ObjectLiteral grammar instead of reusing it, to allow = and : as alternatives for assign and define, respectively; and for any other reason. Sometimes pattern languages diverge from expression grammars for good reason.

Computed Keys

Erik Arvidsson:

  • Today, properties are static and knowable, computed keys are not knowable.

Resolution: Deferred.

But just to capture all the nuance, the idea of @privateName: value in an object literal has support and maintains the compile-time name structure that EA rightly cited.

The [anyExpr]: value idea for a property definition in an object literal is what I believe died today. If you want to extend an object with a computed property name, use assignment or Object.defineProperty.

Weak Refs

Yehuda Katz:

  • Use case: observers

Resolution: Continued, due to lack of time.

BE: valid use-case for observers, virtualization layers, other such bridging functions. MM/AWB need to discuss more, ideally here on es-discuss!

Value Objects

Brendan demos, explanation of the implementation and operator overloading

See bugzilla.mozilla.org/show_bug.cgi?id=749786 and stay tuned.

Thanks again, Rick!

# Rick Waldron (12 years ago)

Thanks for filling in those blanks

# Norbert Lindenberg (12 years ago)

A few additional notes on the items related to internationalization.

Norbert

On May 23, 2012, at 17:58 , Rick Waldron wrote:

4.14, Unicode (Norbert Lindenderg)

NL:

norbertlindenberg.com/2012/05/ecmascript-supplementary-characters/full-unicode-in-ecmascript.pdf

AWB:

  • Concretely, should supplementary characters gain coverage in the currently developing draft.

MM:

  • Mention of spec modularity

AWB:

  • Implication for strings etc.

NL, LH, MM:

  • Any objections? No.

AWB:

  • Canonicalize everything to full unicode grammar
  • Don't think this will change implementation rules

LH:

  • Asks for confirmation

NL, AWB:

  • Confirms no difference.

Resolution: Promoted unanimously to harmony status

I've inserted a copy of my proposal into the Harmony section of the wiki (I wish the wiki had better support for content created in HTML...): harmony:unicode_supplementary_characters and updated Allen's proposals, one to indicate that it's been superseded, the other to indicate that it's still valid and complementary to the accepted proposal: strawman:support_full_unicode_in_strings, strawman:full_unicode_source_code

More detail on the regular expression issue mentioned: esdiscuss/2012-May/022665

4.11, Daylight Savings (Luke Hoban)

Move to remove/reword:

15.9.1.8 "An implementation of ECMAScript is expected to determine the daylight saving time algorithm."

AWB:

  • There needs to be a specification of some sort, as other aspects of the standard rely on this.

more discussion.

Some locales do change

LH:

  • Operating systems and browser do have disagreements

AWB:

  • Either NL or LH can draft replacement text for 15.9.1.6 and 15.9.1.8

more discussion.

Resolution: Remove the spec text, new additions will be considered as new proposal

Not errata.

The basis for the discussion were: esdiscuss/2012-March/020830, esdiscuss/2012-March/020832

Sections to be updated for Harmony are 15.9.1.7 and 15.9.1.8.

String.prototype.toArray

Resolution: Removal from draft.

The reason is that this operation would break a string into UTF-16 code units, so supplementary characters would be broken up. The same functionality (with the same problem) is already available as str.split(""); there's no need to make this problematic functionality more convenient.

# Herby Vojčík (12 years ago)

Rick Waldron wrote:

super

LH:

  • This may be too confusing for the common user

AWB:

  • Asserts that super is defined correctly for classes (explanation)

Should super be allowed in all function forms or restricted to classes?

Resolution: Defer super outside of classes

Any chance to get this back to any (constructor or concise method) functions?

# David Bruant (12 years ago)

Thanks for the notes and complements :-)

Le 24/05/2012 04:43, Brendan Eich a écrit :

Rick Waldron wrote:

Triangle

Is capable of giving up private names

If people have proto they will not use <|.

I don't know who are "people" but I'm not one of them. <| offered some nice sugar with regard to constructors. Just sugar but it was convenient.

MM:

  • From a security perspective, I'd like to move proto out of annex B and into normative body

BE:

  • If MS puts proto in IE, then it becomes defacto standard and we might as well put it in the standard.
  1. proto
  2. grawlix

Resolution: Indefinite postpone\

I.e., we defer/cancel triangle and go with normative mandatory proto. W00t! Kidding, mostly, but I perpetrated it, it is in all browsers but IE, and IE feels the heat on mobile (thank you Thomas Fuchs!). So proto is the winner already, we're just trying to forestall the inevitable.

It seems that "delete Object.prototype.proto" would be the first line I'd write if I wanted to prevent proto from being harmful. However, since <| is out, after doing the delete, the use cases it was intended for (array subclassing is zepto.js' use case, right?) cannot be achieved anymore.

I think we can only recover is if it's possible to extract a proto setter before the delete. I haven't seen a resolution on the proto-related notes, but considering that <| is out, can it be consider to just do a setter?

Once we're at it, for the sake of completeness there is probably no harm in adding a Reflect.setPrototype at this point, is there?

# Brendan Eich (12 years ago)

David Bruant wrote:

Thanks for the notes and complements :-)

Le 24/05/2012 04:43, Brendan Eich a écrit :

Rick Waldron wrote:

Triangle

Is capable of giving up private names

If people have proto they will not use <|. I don't know who are "people" but I'm not one of them. <| offered some nice sugar with regard to constructors. Just sugar but it was convenient.

The argument Rick summarized by "If people have proto they will not use <|" was a bit more nuanced.

If people have to write code for pre-ES6 and ES6 browsers, then even if ES6 has <| support, because proto is coming to ECMA-262 (either in Annex B as normative optional, or in the main normative-mandatory spec), and therefore Microsoft will finally implement proto, any people who are writing JS for old and new browsers -- particularly mobile browsers where IE has too little share to count today -- will use proto only.

New syntax requires a transpiler at least. That's too high a tax if there's already a de-facto standard API such as proto that developers can use that works on older and new browsers in their addressable target markets.

Aside from this point, a separate point: <| is sugar but it looks bad (in my font, right now, in fact) in too many renderings. So even ignoring the point above, <| faced serious grawlix and looks-ugly-in-too-many-fonts objections.

MM:

  • From a security perspective, I'd like to move proto out of annex B and into normative body

BE:

  • If MS puts proto in IE, then it becomes defacto standard and we might as well put it in the standard.
  1. proto
  2. grawlix

Resolution: Indefinite postpone\

I.e., we defer/cancel triangle and go with normative mandatory proto. W00t! Kidding, mostly, but I perpetrated it, it is in all browsers but IE, and IE feels the heat on mobile (thank you Thomas Fuchs!). So proto is the winner already, we're just trying to forestall the inevitable. It seems that "delete Object.prototype.proto" would be the first line I'd write if I wanted to prevent proto from being harmful. However, since <| is out, after doing the delete, the use cases it was intended for (array subclassing is zepto.js' use case, right?

Not just array -- DOM too.

) cannot be achieved anymore.

So don't delete proto :-P.

Really, you can't have it both ways. If you want Zepto, you are not running SES code. Let's see if someone can "cajole" Zepto and then talk.

I think we can only recover is if it's possible to extract a proto setter before the delete. I haven't seen a resolution on the proto-related notes, but considering that <| is out, can it be consider to just do a setter?

No, we agreed that adds a new hazard not present in almost all browsers today or over the last 12 years: an extractable setter. We agreed to spec proto as a magic data property.

Once we're at it, for the sake of completeness there is probably no harm in adding a Reflect.setPrototype at this point, is there?

There is, just as there's a cost to Object.setPrototypeOf (the obvious place to put it to match Object.getPrototypeOf from ES5). Mark pointed out that he'd have to delete that static method too, and from every frame that might run SES code. But when mashing up SES and non-SES code, it would be better not to break the non-SES code by such deletion.

Having only the SES environment's Object.prototype.proto to delete is better.

# Tom Van Cutsem (12 years ago)

If proto is getting standardized, I propose we adapt proxies to be able to trap getPrototypeOf.

Why?

  • with proto, stable prototypes are no longer an invariant. It's awkward to make proxies go out of their way to maintain it still.

  • it's much more consistent with all the other Object.* methods: Object.keys(proxy) => calls keys trap

Object.getPrototypeOf(proxy) => calls getPrototypeOf trap

  • it makes membranes much simpler, because they can now do: getPrototypeOf: function(target) { return wrap(Object.getPrototypeOf(target)); } This saves the extra object allocation to create a dummy target with a wrapped prototype.

To be consistent with the other traps, if we buy into a getPrototypeOf trap, we should add a getPrototypeOf method in the "reflect" module as well (basically an alias for Object.getPrototypeOf).

Your thoughts?

Cheers, Tom

2012/5/24 Brendan Eich <brendan at mozilla.com>

# David Bruant (12 years ago)

Le 26/05/2012 13:53, Tom Van Cutsem a écrit :

Hi,

If proto is getting standardized, I propose we adapt proxies to be able to trap getPrototypeOf.

Why?

  • with proto, stable prototypes are no longer an invariant. It's awkward to make proxies go out of their way to maintain it still.

This is very true.

  • it's much more consistent with all the other Object.* methods: Object.keys(proxy) => calls keys trap Object.getPrototypeOf(proxy) => calls getPrototypeOf trap

  • it makes membranes much simpler, because they can now do: getPrototypeOf: function(target) { return wrap(Object.getPrototypeOf(target)); } This saves the extra object allocation to create a dummy target with a wrapped prototype.

To be consistent with the other traps, if we buy into a getPrototypeOf trap, we should add a getPrototypeOf method in the "reflect" module as well (basically an alias for Object.getPrototypeOf).

Your thoughts?

I agree a lot with your rationale. I have no comment on the "how", but what you said makes sense.

Additionally, I'd like to add that if proto gets in the spec, it should be clearly stated that proxy.proto calls the get and set traps and does not get/set the prototype of the proxy without being trapped.

# Brendan Eich (12 years ago)

Tom Van Cutsem wrote:

If proto is getting standardized, I propose we adapt proxies to be able to trap getPrototypeOf.

Why?

  • with proto, stable prototypes are no longer an invariant. It's awkward to make proxies go out of their way to maintain it still.

  • it's much more consistent with all the other Object.* methods: Object.keys(proxy) => calls keys trap Object.getPrototypeOf(proxy) => calls getPrototypeOf trap

  • it makes membranes much simpler, because they can now do: getPrototypeOf: function(target) { return wrap(Object.getPrototypeOf(target)); } This saves the extra object allocation to create a dummy target with a wrapped prototype.

To be consistent with the other traps, if we buy into a getPrototypeOf trap, we should add a getPrototypeOf method in the "reflect" module as well (basically an alias for Object.getPrototypeOf).

Your thoughts?

Perfect! Thanks for tracking the notes and suggesting all this. I'll leave it to you, Allen, and whoever else is interested to work out spec details.

# Brandon Benvie (12 years ago)

Excellent! It's actually kind of awkward already if you don't create a pseudo-trap for 'proto' since treating the property like normal ones leads to incorrect results for various operations like defineProperty, and it doesn't follow normal rules for showing up in property names listing. It's still much more common to find code using 'proto' than Object.getProtototypeOf, even just as a getter.

# John J Barton (12 years ago)

On Thu, May 24, 2012 at 11:10 AM, Brendan Eich <brendan at mozilla.com> wrote:

David Bruant wrote:

Once we're at it, for the sake of completeness there is probably no harm in adding a Reflect.setPrototype at this point, is there?

There is, just as there's a cost to Object.setPrototypeOf (the obvious place to put it to match Object.getPrototypeOf from ES5). Mark pointed out that he'd have to delete that static method too, and from every frame that might run SES code. But when mashing up SES and non-SES code, it would be better not to break the non-SES code by such deletion.

Having only the SES environment's Object.prototype.proto to delete is better.

How is this this line of reasoning -- which I read as 'support for SES-environments and non-SES-environments' -- not violating 1JS?

jjb

# Brendan Eich (12 years ago)

John J Barton wrote:

On Thu, May 24, 2012 at 11:10 AM, Brendan Eich<brendan at mozilla.com> wrote:

David Bruant wrote:

Once we're at it, for the sake of completeness there is probably no harm in adding a Reflect.setPrototype at this point, is there? There is, just as there's a cost to Object.setPrototypeOf (the obvious place to put it to match Object.getPrototypeOf from ES5). Mark pointed out that he'd have to delete that static method too, and from every frame that might run SES code. But when mashing up SES and non-SES code, it would be better not to break the non-SES code by such deletion.

Having only the SES environment's Object.prototype.proto to delete is better.

How is this this line of reasoning -- which I read as 'support for SES-environments and non-SES-environments' -- not violating 1JS?

How about you say how it violates 1JS instead of asking me to prove a negative?

1JS is about no explicit version number/MIME-type-parameter/pragma/other-designator opt-in. Nothing to do with goal #5 at harmony:harmony#goals, which is about a different language, SES, that must map efficiently to ES6 and up (and almost does to ES5).

Subset and other transpiled language != version opt-in mandated to use ES6 in the main language.

# Brandon Benvie (12 years ago)

proto has no effect on 1JS. It introduces no new syntax and is partially polyfillable. Poorly and incompletely, but is doable to an extent and definitely isn't backward hostile in the way that pragmas and new syntax are.

# John J Barton (12 years ago)

On Sun, May 27, 2012 at 4:41 PM, Brendan Eich <brendan at mozilla.com> wrote:

John J Barton wrote:

On Thu, May 24, 2012 at 11:10 AM, Brendan Eich<brendan at mozilla.com>  wrote:

David Bruant wrote:

Once we're at it, for the sake of completeness there is probably no harm in adding a Reflect.setPrototype at this point, is there?

There is, just as there's a cost to Object.setPrototypeOf (the obvious place to put it to match Object.getPrototypeOf from ES5). Mark pointed out that he'd have to delete that static method too, and from every frame that might run SES code. But when mashing up SES and non-SES code, it would be better not to break the non-SES code by such deletion.

Having only the SES environment's Object.prototype.proto to delete is better.

How is this this line of reasoning -- which I read as 'support for SES-environments and non-SES-environments' -- not violating 1JS?

How about you say how it violates 1JS instead of asking me to prove a negative?

I wasn't asking for a proof. I was just asking a question.

1JS is about no explicit version number/MIME-type-parameter/pragma/other-designator opt-in. Nothing to do with goal #5 at harmony:harmony#goals, which is about a different language, SES, that must map efficiently to ES6 and up (and almost does to ES5).

Subset and other transpiled language != version opt-in mandated to use ES6 in the main language.

The reason I asked is that "use strict" seems to be a subset but acts like another version in some cases. In particular, if a library uses obj.freeze() and the caller modifies the object by adding a property, the caller gets no error message. (You'll have to read the source of the library to figure it out.) The library is, for this purpose, operating in a language where object modification is an error but the caller is not.

If 'mashing up' is similar to 'using objects from a library', then isn't JS-mashed-with-SES (whatever that means) a different version of JS?

jjb

# Allen Wirfs-Brock (12 years ago)

On May 27, 2012, at 5:13 PM, John J Barton wrote:

... The reason I asked is that "use strict" seems to be a subset but acts like another version in some cases. In particular, if a library uses obj.freeze() and the caller modifies the object by adding a property, the caller gets no error message. (You'll have to read the source of the library to figure it out.) The library is, for this purpose, operating in a language where object modification is an error but the caller is not.

A don't follow your logic. "Freezing" is independent of strict mode. It is a characteristic of the object model, not the source code "mode". What is determined by strict mode is what happens when code for that mode tries to modify a frozen object. It can either cause an exception (strict mode) or for be silently ignored (non-strict mode).

If the library writer thinks that freezing will always cause exceptions, then they don't understand either strict mode or what Object.freeze actually does. I would generally have higher expectations for library writers.

First rule of strict mode: "use strict" only affects code that is lexically within the scope of the directive. It has no global effect.

If 'mashing up' is similar to 'using objects from a library', then isn't JS-mashed-with-SES (whatever that means) a different version of JS?

Yes...no...when passing object into any library you need to be aware of the library's expectations for those objects. It should be part of the documented interface contract for the library. strict/non-strict, SES or plain old JS, garbage in usually results in garbage out

# John J Barton (12 years ago)

On Sun, May 27, 2012 at 6:04 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On May 27, 2012, at 5:13 PM, John J Barton wrote:

... The reason I asked is that "use strict" seems to be a subset but acts like another version in some cases. In particular, if a library uses obj.freeze() and the caller modifies the object by adding a property, the caller gets no error message. (You'll have to read the source of the library to figure it out.) The library is, for this purpose, operating in a language where object modification is an error but the caller is not.

A don't follow your logic.  "Freezing" is independent of  strict mode.  It is a characteristic of the object model, not the source code "mode". What is determined by strict mode is what happens when code for that mode tries to modify a frozen object.  It can either cause an exception (strict mode) or for be silently ignored (non-strict mode).

Freezing is not independent of strict mode because a frozen object can be passed between strict and non-strict mode source code. The object behaves differently in these two environments.

When a frozen object is passed to normal JavaScript code, normal JavaScript operations silently fail. IMO this is the worst kind of modal language result.

If the library writer thinks that freezing will always cause exceptions, then they don't understand either strict mode or what Object.freeze actually does.  I would generally have higher expectations for library writers.

I have higher expectations for the language: modifying frozen objects should always throw exceptions.

First rule of strict mode:  "use strict" only affects code that is lexically within the scope of the directive.  It has no global effect.

My example contradicts this claim.

If 'mashing up' is similar to 'using objects from a library', then isn't JS-mashed-with-SES (whatever that means) a different version of JS?

Yes...no...when passing object into any library you need to be aware of the library's expectations for those objects.  It should be part of the documented interface contract for the library. strict/non-strict, SES or plain old JS, garbage in usually results in garbage out

In this case the library provides the objects. Of course your truism applies, but to me, objects with silent new behavior should not be a matter of documentation.

jjb

# Allen Wirfs-Brock (12 years ago)

On May 27, 2012, at 6:42 PM, John J Barton wrote:

On Sun, May 27, 2012 at 6:04 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On May 27, 2012, at 5:13 PM, John J Barton wrote:

... The reason I asked is that "use strict" seems to be a subset but acts like another version in some cases. In particular, if a library uses obj.freeze() and the caller modifies the object by adding a property, the caller gets no error message. (You'll have to read the source of the library to figure it out.) The library is, for this purpose, operating in a language where object modification is an error but the caller is not.

A don't follow your logic. "Freezing" is independent of strict mode. It is a characteristic of the object model, not the source code "mode". What is determined by strict mode is what happens when code for that mode tries to modify a frozen object. It can either cause an exception (strict mode) or for be silently ignored (non-strict mode).

Freezing is not independent of strict mode because a frozen object can be passed between strict and non-strict mode source code. The object behaves differently in these two environments.

No that's not how it is specified. Freezing works exactly the same and is mode independent. What varies between modes is the semantics of the assignment operator which is defined in terms of the PutValue abstract operation. PutValue responds differently to frozen objects based upon whether the assignment occurs in strict or non-strict code.

When a frozen object is passed to normal JavaScript code, normal JavaScript operations silently fail. IMO this is the worst kind of modal language result.

It is modal, but it is a characteristic of the code not the object.

If the library writer thinks that freezing will always cause exceptions, then they don't understand either strict mode or what Object.freeze actually does. I would generally have higher expectations for library writers.

I have higher expectations for the language: modifying frozen objects should always throw exceptions.

First, you need to realize that there is really no such thing as a "frozen object". Individual properties may be non-configurable and non-writable. The object itself is either extensible or non-extensible (properties may/may-not be added). ES1-3 already defined the behavior of assigning to non-writable property. Such writes were specified by ES1-3 to be silently ignore. To do otherwise in non-strict ES5 would have been a breaking change. Non-extensible objects were a new concept for ES5. You can debate the chosen behavior, but for non-strict code it is generally consistent with how ES has traditionally handled similar impossible to fulfill requests. It is what it is.

First rule of strict mode: "use strict" only affects code that is lexically within the scope of the directive. It has no global effect.

My example contradicts this claim.

No, read the spec. You seem to be perceiving something different than what is actually occurring.

If 'mashing up' is similar to 'using objects from a library', then isn't JS-mashed-with-SES (whatever that means) a different version of JS?

Yes...no...when passing object into any library you need to be aware of the library's expectations for those objects. It should be part of the documented interface contract for the library. strict/non-strict, SES or plain old JS, garbage in usually results in garbage out

In this case the library provides the objects. Of course your truism applies, but to me, objects with silent new behavior should not be a matter of documentation.

that would be an alternative design (for the non-extensible case of trying to add a new property) but it's not the design that was chosen for ES5. Whether you like or dislike the that choice, it's water under the bridge.

# John J Barton (12 years ago)

On Sun, May 27, 2012 at 10:09 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote: ...

First rule of strict mode:  "use strict" only affects code that is lexically within the scope of the directive.  It has no global effect.

My example contradicts this claim.

No, read the spec.  You seem to be perceiving something different than what is actually occurring.

Yes perception is exactly what I am talking about: the perception of 1JS.

Step back from the spec for a second and look at what is actually occurring.

A library writer creates an object in one scope and all of their tests succeed. I use it another scope and my code fails. We are both using legal statements. How can this not be a global effect?

Now I grant you that this effect is not an operation of the compiler or runtime. Rather the effect here is that the library writer is operating under one perception of 1JS and I am operating under another perception of 1JS. Both of our perceptions are 100% valid. Ergo we do not have 1JS.

If 'mashing up' is similar to 'using objects from a library', then isn't JS-mashed-with-SES (whatever that means) a different version of JS?

Yes...no...when passing object into any library you need to be aware of the library's expectations for those objects.  It should be part of the documented interface contract for the library. strict/non-strict, SES or plain old JS, garbage in usually results in garbage out

In this case the library provides the objects. Of course your truism applies, but to me, objects with silent new behavior should not be a matter of documentation.

that would be an alternative design (for the non-extensible case of trying to add a new property) but it's not the design that was chosen for ES5.  Whether you like or dislike the that choice, it's water under the bridge.

Exactly why I brought up this subject when I saw SES+non-SES: I don't want more water under this bridge. I dislike object.freeze() altogether, not because it's a bad idea but because it's not a JavaScript idea. But I didn't realize how truly horrible it was until I discovered that it is silent and that silence is modal.

Perhaps that mistake is done. Let's not have another. Let's have 1JS. Not 1JS with modes or 1JS with environments, just 1JS.

jjb

# David Bruant (12 years ago)

Le 28/05/2012 01:37, John J Barton a écrit :

On Thu, May 24, 2012 at 11:10 AM, Brendan Eich<brendan at mozilla.com> wrote:

David Bruant wrote:

Once we're at it, for the sake of completeness there is probably no harm in adding a Reflect.setPrototype at this point, is there?

There is, just as there's a cost to Object.setPrototypeOf (the obvious place to put it to match Object.getPrototypeOf from ES5). Mark pointed out that he'd have to delete that static method too, and from every frame that might run SES code. But when mashing up SES and non-SES code, it would be better not to break the non-SES code by such deletion.

Having only the SES environment's Object.prototype.proto to delete is better. How is this this line of reasoning -- which I read as 'support for SES-environments and non-SES-environments' -- not violating 1JS?

My answer would be "it is" in the sense that SES is a subset of JavaScript. Very much like Joe-E for Java (I recommand to read the related paper [1]). But the subset is something really usable. It's also more about programmer discipline than a new programming language itself.

David

[1] www.cs.berkeley.edu/~daw/papers/joe-e-ndss10.pdf

# T.J. Crowder (12 years ago)

On 28 May 2012 06:37, John J Barton <johnjbarton at johnjbarton.com> wrote:

A library writer creates an object in one scope and all of their tests succeed. I use it another scope and my code fails. We are both using legal statements. How can this not be a global effect?

You're both using legal statements in the mode (variant) of the language that you have chosen to use in your execution context. JavaScript has always had read-only properties (ex: Object.prototype, Function#length, Number.MAX_VALUE), and prior to ES5 always had writes to read-only properties fail silently. Object.freeze, Object.defineProperty, and the like give us new ways to create read-only properties, but read-only properties are neither new nor do they create a new "global effect."

Silent write failures are a Bad Thing(tm), so strict mode lets us opt into receiving exceptions when we try to assign to read-only properties. This is local to our execution context, where we have chosen (implicitly or otherwise) to use non-strict or strict mode. Nothing global there either.

I dislike object.freeze()

altogether, not because it's a bad idea but because it's not a JavaScript idea. But I didn't realize how truly horrible it was until I discovered that it is silent and that silence is modal. Perhaps that mistake is done.

For my money, the far bigger mistake would be to have different kinds of read-only properties: Ones that fail silently for legacy reasons, and one that throw even in non-strict mode. Far better to have a consistent view of read-only properties within a given execution context, where the author decides whether they want silent failures or exceptions.

T.J. Crowder Independent Software Engineer tj / crowder software / com www / crowder software / com

# John J Barton (12 years ago)

On May 28, 2012 2:53 AM, "T.J. Crowder" <tj at crowdersoftware.com> wrote:

On 28 May 2012 06:37, John J Barton <johnjbarton at johnjbarton.com> wrote:

A library writer creates an object in one scope and all of their tests succeed. I use it another scope and my code fails. We are both using legal statements. How can this not be a global effect?

You're both using legal statements in the mode (variant) of the language

that you have chosen to use in your execution context.

Unfortunately I am not successful in communicating the problem here.

In the example I described both variants are in the same execution context.

JavaScript has always had read-only properties (ex: Object.prototype, Function#length, Number.MAX_VALUE), and prior to ES5 always had writes to read-only properties fail silently. Object.freeze, Object.defineProperty, and the like give us new ways to create read-only properties, but read-only properties are neither new nor do they create a new "global effect."

How can changes to the object model in a language the supports passing objects not be global?

You and I may both believe our JS is best, but if we share objects then neither gets 1JS.

Silent write failures are a Bad Thing(tm), so strict mode lets us opt

into receiving exceptions when we try to assign to read-only properties. This is local to our execution context, where we have chosen (implicitly or otherwise) to use non-strict or strict mode. Nothing global there either.

I dislike object.freeze() altogether, not because it's a bad idea but because it's not a JavaScript idea. But I didn't realize how truly horrible it was until I discovered that it is silent and that silence is modal. Perhaps that mistake is done.

For my money, the far bigger mistake would be to have different kinds of

read-only properties: Ones that fail silently for legacy reasons, and one that throw even in non-strict mode. Far better to have a consistent view of read-only properties within a given execution context, where the author decides whether they want silent failures or exceptions.

Sorry I don't follow your logic here. I am arguing for more consistency. 1JS, not "author's choice".

jjb

# T.J. Crowder (12 years ago)

On 28 May 2012 17:34, John J Barton <johnjbarton at johnjbarton.com> wrote:

On May 28, 2012 2:53 AM, "T.J. Crowder" <tj at crowdersoftware.com> wrote:

On 28 May 2012 06:37, John J Barton <johnjbarton at johnjbarton.com> wrote:

A library writer creates an object in one scope and all of their tests succeed. I use it another scope and my code fails. We are both using legal statements. How can this not be a global effect?

You're both using legal statements in the mode (variant) of the language that you have chosen to use in your execution context.

Unfortunately I am not successful in communicating the problem here.

In the example I described both variants are in the same execution context.

They cannot be. Strict mode applies throughout the execution context in which it's declared. The library code is within its execution context. Your code is within your context. They are separate. They can communicate, but they are separate.

JavaScript has always had read-only properties (ex: Object.prototype,

Function#length, Number.MAX_VALUE), and prior to ES5 always had writes to read-only properties fail silently. Object.freeze, Object.defineProperty, and the like give us new ways to create read-only properties, but read-only properties are neither new nor do they create a new "global effect."

How can changes to the object model in a language the supports passing objects not be global?

It's not a change to the object model. Again, JavaScript has had read-only properties for a long time (see my examples above), certainly since 1998 and I would assume prior to that as well.

For my money, the far bigger mistake would be to have different kinds of read-only properties: Ones that fail silently for legacy reasons, and one that throw even in non-strict mode. Far better to have a consistent view of read-only properties within a given execution context, where the author decides whether they want silent failures or exceptions.

Sorry I don't follow your logic here. I am arguing for more consistency. 1JS, not "author's choice".

I think you're using 1JS differently than Brendan is, but if so presumably he'll address that.

Regardless of terminology: We can't retroactively change the behavior of read-only properties in non-strict mode, just like we can't retroactively fix the Horror of Implicit Globals, without breaking code that currently works. So that means either A) Making two kinds of read-only property, legacy and modern, where writes to legacy ones continue to fail silently and writes to modern ones throw. Yuck. Or B) Making modern read-only properties behave consistently with the legacy ones, and providing a means to say "I don't care whether they're old or new, I want writes to legacy properties to throw" (and lots of other good stuff; e.g., the strict variant). TC39 very intelligently opted for the second option with ES5. This keeps the old code working, while improving the language.

-- T.J. Crowder Independent Software Engineer tj / crowder software / com www / crowder software / com

# Russell Leggett (12 years ago)

On Mon, May 28, 2012 at 12:34 PM, John J Barton <johnjbarton at johnjbarton.com

wrote:

On May 28, 2012 2:53 AM, "T.J. Crowder" <tj at crowdersoftware.com> wrote:

On 28 May 2012 06:37, John J Barton <johnjbarton at johnjbarton.com> wrote:

A library writer creates an object in one scope and all of their tests succeed. I use it another scope and my code fails. We are both using legal statements. How can this not be a global effect?

You're both using legal statements in the mode (variant) of the language that you have chosen to use in your execution context.

Unfortunately I am not successful in communicating the problem here.

In the example I described both variants are in the same execution context.

Perhaps this discussion would be aided by a more concrete example. Let's assume three files - lib.js, test.js and app.js. John, I believe in your example, lib and test would be written for strict mode, and app would be non-strict.

======= lib.js =========== "use strict"; //lib code here

======= test.js ========== "use strict"; //test code here, testing object from lib

======= app.js ========== //app code here using object from lib

Fill in the gaps with something simple and I think we'll be able to get this sorted. I think there might be a communication issue here.

# T.J. Crowder (12 years ago)

On 28 May 2012 18:46, Russell Leggett <russell.leggett at gmail.com> wrote:

Perhaps this discussion would be aided by a more concrete example.

Doh! Excellent idea. John, if you'd like...? (Otherwise I can do one.)

-- T.J.

# Brendan Eich (12 years ago)

David Bruant wrote:

Le 28/05/2012 01:37, John J Barton a écrit :

On Thu, May 24, 2012 at 11:10 AM, Brendan Eich<brendan at mozilla.com>
wrote:

David Bruant wrote:

Once we're at it, for the sake of completeness there is probably no harm in adding a Reflect.setPrototype at this point, is there?

There is, just as there's a cost to Object.setPrototypeOf (the obvious place to put it to match Object.getPrototypeOf from ES5). Mark pointed out that he'd have to delete that static method too, and from every frame that might run SES code. But when mashing up SES and non-SES code, it would be better not to break the non-SES code by such deletion.

Having only the SES environment's Object.prototype.proto to delete is better. How is this this line of reasoning -- which I read as 'support for SES-environments and non-SES-environments' -- not violating 1JS? My answer would be "it is" in the sense that SES is a subset of JavaScript.

Sorry, no. Version opt-in != subset. There is a very large number of subsets of any single version of JS. 1JS is about not requiring you to say

<script type="application/ecmascript;version=6">...</script>

or

use version 6;

or any such thing in order to use new syntax.

Very much like Joe-E for Java (I recommand to read the related paper [1]). But the subset is something really usable.

Usability is not relevant to the question of whether subsets violate 1JS. Subsets do not violate 1JS. Even a subset that the spec and harmony goals explicitly identity (informally) as to be supported does not create version opt-in.

John then went on to ask about Object.freeze but that affects object and property attributes, which are heap not code as Allen points out. They do not create version opt-in mandates either.

Yes, people writing libraries have to take care what they produce and consume. No, this isn't version opt-in.

# John J Barton (12 years ago)

On Mon, May 28, 2012 at 10:50 AM, T.J. Crowder <tj at crowdersoftware.com> wrote:

On 28 May 2012 18:46, Russell Leggett <russell.leggett at gmail.com> wrote:

Perhaps this discussion would be aided by a more concrete example.

Doh! Excellent idea. John, if you'd like...? (Otherwise I can do one.)

Here's mine: Source: johnjbarton/webdev-examples/tree/gh-pages/Freeze Site: johnjbarton.github.com/webdev-examples/Freeze/app.html

The application function app() calls the library function makeExample(), adds a method to it, then calls that method: function app() { var r = makeExample(); r.discover = function() { console.log("I want to call this function"); return 1; }; r.discover(); }

The result is an error message at the Uncaught TypeError: Object #<Object> has no method 'discover'.

Note that lib.js is to be written by someone else and overall they do a great job. They choose 'use strict' and freeze(); that decision is sound.

I am calling that library. I extend their object in order to fit it into other libraries I use.

Now imagine that r.discover() is call somewhere else and -- I know this is hard -- imagine you know nothing about the discussion above.

Maybe my debug skills are not great, but I eventually had to resort to executing the library code single stepping to figure out why the method call failed.

I want to just re-iterate that the issue here is not my negative opinions on the two ingredients, 'use strict' (IMO pointless extra typing) and 'freeze() (IMO not JS). The issue here is the modal object model created from the combination and how to avoid repeating that mistake. Without the modal object model, the library writer can 'use strict' and 'freeze()', and I can live with the result or not use the library. With the modal object model I don't get a choice: I have to debug the library line by line to discover I can't use it.

jjb

# John Tamplin (12 years ago)

On Tue, May 29, 2012 at 12:07 AM, John J Barton <johnjbarton at johnjbarton.com

wrote:

function app() { var r = makeExample(); r.discover = function() { console.log("I want to call this function"); return 1; }; r.discover(); }

The result is an error message at the Uncaught TypeError: Object #<Object> has no method 'discover'.

Isn't this code broken in either case? The only question is whether you get an exception when you create discover() or when you call it. Your code can choose or not to treat adding properties to frozen objects as a fatal error or not, but the code is going to fail if r is frozen no matter what.

# Russell Leggett (12 years ago)

On Tue, May 29, 2012 at 12:07 AM, John J Barton <johnjbarton at johnjbarton.com

wrote:

On Mon, May 28, 2012 at 10:50 AM, T.J. Crowder <tj at crowdersoftware.com> wrote:

On 28 May 2012 18:46, Russell Leggett <russell.leggett at gmail.com> wrote:

Perhaps this discussion would be aided by a more concrete example.

Doh! Excellent idea. John, if you'd like...? (Otherwise I can do one.)

Here's mine: Source: johnjbarton/webdev-examples/tree/gh-pages/Freeze Site: johnjbarton.github.com/webdev-examples/Freeze/app.html

The application function app() calls the library function makeExample(), adds a method to it, then calls that method: function app() { var r = makeExample(); r.discover = function() { console.log("I want to call this function"); return 1; }; r.discover(); }

The result is an error message at the Uncaught TypeError: Object #<Object> has no method 'discover'.

This would be the case no matter whether the library were written in strict mode or not. Because you aren't using strict, you don't get the initial error when you try to write to the frozen object.

Note that lib.js is to be written by someone else and overall they do a great job. They choose 'use strict' and freeze(); that decision is sound.

I am calling that library. I extend their object in order to fit it into other libraries I use.

Now imagine that r.discover() is call somewhere else and -- I know this is hard -- imagine you know nothing about the discussion above.

Maybe my debug skills are not great, but I eventually had to resort to executing the library code single stepping to figure out why the method call failed.

This just goes to show that it was useful to add the error to strict mode. Are you suggesting that the error should throw even in non-strict mode?

I want to just re-iterate that the issue here is not my negative opinions on the two ingredients, 'use strict' (IMO pointless extra typing) and 'freeze() (IMO not JS). The issue here is the modal object model created from the combination and how to avoid repeating that mistake. Without the modal object model, the library writer can 'use strict' and 'freeze()', and I can live with the result or not use the library. With the modal object model I don't get a choice: I have to debug the library line by line to discover I can't use it.

It seems to me that your problem is really that you dislike non-strict mode's behavior when trying to modify a frozen object. This has nothing to do with what you call a modal object model. There is nothing different about the object because it came from a strict environment vs a non-strict environment. It has to do with you using it in a strict vs non-strict environment. Really its like deciding whether or not to use the gcc -Werror flag, which you can use to turn warnings into errors. Granted, in this case you don't even get a warning, but you get the idea.

# John J Barton (12 years ago)

On Mon, May 28, 2012 at 9:33 PM, John Tamplin <jat at google.com> wrote:

On Tue, May 29, 2012 at 12:07 AM, John J Barton <johnjbarton at johnjbarton.com> wrote:

function app() {  var r = makeExample();  r.discover = function() {    console.log("I want to call this function");    return 1;  };  r.discover(); }

The result is an error message at the Uncaught TypeError: Object #<Object> has no method 'discover'.

Isn't this code broken in either case?

Yes, this is correct.

The only question is whether you get an exception when you create discover() or when you call it.  Your code can choose or not to treat adding properties to frozen objects as a fatal error or not, but the code is going to fail if r is frozen no matter what.

This is not correct. (Well to be sure, I am assuming that you meant to write: "You can choose..." because, of course, 'code' cannot choose.)

I do not have this choice. I wrote the code and I got the error.

Here is where I am asking you to imagine the real-life situation, not the exercise of a few lines of code.

If I had a magic translation book that said "oh, you know that Uncaught TypeError: Object #<Object> has no method 'discover', really

means you tried to modify a frozen object", then I would have a choice. No such book exists to the best of my knowledge.

jjb

# John Tamplin (12 years ago)

On Tue, May 29, 2012 at 12:45 AM, John J Barton <johnjbarton at johnjbarton.com

wrote:

The only question is whether you get an exception when you create discover() or when you call it. Your code can choose or not to treat adding properties to frozen objects as a fatal error or not, but the code is going to fail if r is frozen no matter what.

This is not correct. (Well to be sure, I am assuming that you meant to write: "You can choose..." because, of course, 'code' cannot choose.)

I do not have this choice. I wrote the code and I got the error.

You have the choice of using strict mode in your code, and getting the error when you try and create discover(). Note that the decision embodied in your code is independent of the decision made by the library writer, as the same would apply if the library were written in non-strict mode.

Regarding the original decision to have silent failures on modifying a frozen object, that is just one of many quirks you just have to know if you are going to write JS. Just like putting a line break after a return keyword, you only have to do it once and you will remember not to do it again.

# John J Barton (12 years ago)

On Mon, May 28, 2012 at 9:41 PM, Russell Leggett <russell.leggett at gmail.com> wrote:

On Tue, May 29, 2012 at 12:07 AM, John J Barton <johnjbarton at johnjbarton.com> wrote:

On Mon, May 28, 2012 at 10:50 AM, T.J. Crowder <tj at crowdersoftware.com> wrote:

On 28 May 2012 18:46, Russell Leggett <russell.leggett at gmail.com> wrote:

Perhaps this discussion would be aided by a more concrete example.

Doh! Excellent idea. John, if you'd like...? (Otherwise I can do one.)

Here's mine: Source: johnjbarton/webdev-examples/tree/gh-pages/Freeze Site: johnjbarton.github.com/webdev-examples/Freeze/app.html

The application function app() calls the library function makeExample(), adds a method to it, then calls that method: function app() {  var r = makeExample();  r.discover = function() {    console.log("I want to call this function");    return 1;  };  r.discover(); }

The result is an error message at the Uncaught TypeError: Object #<Object> has no method 'discover'.

This would be the case no matter whether the library were written in strict mode or not. Because you aren't using strict, you don't get the initial error when you try to write to the frozen object.

Note that lib.js is to be written by someone else and overall they do a great job. They choose 'use strict' and freeze(); that decision is sound.

I am calling that library. I extend their object in order to fit it into other libraries I use.

Now imagine that r.discover() is call somewhere else and -- I know this is hard -- imagine you know nothing about the discussion above.

Maybe my debug skills are not great, but I eventually had to resort to executing the library code single stepping to figure out why the method call failed.

This just goes to show that it was useful to add the error to strict mode. Are you suggesting that the error should throw even in non-strict mode?

No. I am suggesting that Object.freeze() should not have been added to the language unless an error was thrown when the object is modified, full stop. Having a feature like Object.freeze() that does not give an error when you modify the object is unreasonable. I'm completely baffled that reasonable engineers would disagree with this position.

The coupling between freeze() and "use strict" comes exactly because library engineers would not use freeze() if they knew that it gave no errors. But because the library engineers "use strict" they don't know that their users may suffer from this language defect.

Or to say it another way, if the error were thrown in non-strict mode, then I would not complain to you I would complain to the library writer.

Again "should not have been" means "let's not make this mistake again".

I want to just re-iterate that the issue here is not my negative opinions on the two ingredients, 'use strict' (IMO pointless extra typing) and 'freeze() (IMO not JS).   The issue here is the modal object model created from the combination and how to avoid repeating that mistake.  Without the modal object model, the library writer can 'use strict' and 'freeze()', and I can live with the result or not use the library. With the modal object model I don't get a choice: I have to debug the library line by line to discover I can't use it.

It seems to me that your problem is really that you dislike non-strict mode's behavior when trying to modify a frozen object. This has nothing to do with what you call a modal object model. There is nothing different about the object because it came from a strict environment vs a non-strict environment.

You are looking at the wrong part of this problem. You are looking at the object. This problem is not about the object.

The problem is the library is built and tested under 'use strict' where freeze() makes sense to apply because it will prevent some kinds of problems and not cause more.

But the use of the library is not under 'use strict' and freeze() is not reasonable.

The object is the same, but the library writer and I have very different assumptions about the object. We are both doing reasonable programming with different object models. That is the problem.

jjb

# John J Barton (12 years ago)

On Mon, May 28, 2012 at 9:54 PM, John Tamplin <jat at google.com> wrote:

On Tue, May 29, 2012 at 12:45 AM, John J Barton <johnjbarton at johnjbarton.com> wrote:

The only question is whether you get an exception when you create discover() or when you call it.  Your code can choose or not to treat adding properties to frozen objects as a fatal error or not, but the code is going to fail if r is frozen no matter what.

This is not correct. (Well to be sure, I am assuming that you meant to write:  "You can choose..." because, of course, 'code' cannot choose.)

I do not have this choice. I wrote the code and I got the error.

You have the choice of using strict mode in your code, and getting the error when you try and create discover().  Note that the decision embodied in your code is independent of the decision made by the library writer, as the same would apply if the library were written in non-strict mode.

Regarding the original decision to have silent failures on modifying a frozen object, that is just one of many quirks you just have to know if you are going to write JS.  Just like putting a line break after a return keyword, you only have to do it once and you will remember not to do it again.

So your stand is that we should continue to add quirks to the language? I guess not.

So let's rewind to my original question. If the discussion about SES is leading us toward more things like freeze(), let's do a better job this time.

jjb

# Axel Rauschmayer (12 years ago)

No. I am suggesting that Object.freeze() should not have been added to the language unless an error was thrown when the object is modified, full stop. Having a feature like Object.freeze() that does not give an error when you modify the object is unreasonable. I'm completely baffled that reasonable engineers would disagree with this position.

The coupling between freeze() and "use strict" comes exactly because library engineers would not use freeze() if they knew that it gave no errors. But because the library engineers "use strict" they don't know that their users may suffer from this language defect.

Or to say it another way, if the error were thrown in non-strict mode, then I would not complain to you I would complain to the library writer.

Again "should not have been" means "let's not make this mistake again".

Not I get what you mean: You are saying that if, as a library writer, you want to use freeze the “proper” way, you have to force library clients to use strict mode.

Don’t forget, though, that strict mode is a paraphrase for “JavaScript how it should be”. So there must be a rationale behind making it fail silently in non-strict mode.

I personally don’t mind too much, because the object is frozen either way, things just fail much later in non-strict mode.

# Allen Wirfs-Brock (12 years ago)

On May 28, 2012, at 10:03 PM, John J Barton wrote:

So let's rewind to my original question. If the discussion about SES is leading us toward more things like freeze(), let's do a better job this time.

John, could you xplain what you would have done differently with "freeze()". It's water under the bridge, but perhaps if you can explain what you would have done we will be better able to understand your concerns.

# John J Barton (12 years ago)

On Mon, May 28, 2012 at 10:09 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On May 28, 2012, at 10:03 PM, John J Barton wrote:

So let's rewind to my original question.  If the discussion about SES is leading us toward more things like freeze(), let's do a better job this time.

John, could you xplain what you would have done differently with "freeze()".  It's water under the bridge, but perhaps if you can explain what you would have done we will be better able to understand your concerns.

I would ask that the bar for the "freeze()" feature include exceptions on modifications. If this is not feasible, the feature cannot be accepted.

If, as seems to be the case, the exceptions are only possible once ES mandates "use strict", then freeze() must wait for that fine day.

I believe that is a sensible model.

jjb

# Brendan Eich (12 years ago)

John J Barton wrote:

On Mon, May 28, 2012 at 10:09 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On May 28, 2012, at 10:03 PM, John J Barton wrote:

So let's rewind to my original question. If the discussion about SES is leading us toward more things like freeze(), let's do a better job this time.

John, could you xplain what you would have done differently with "freeze()". It's water under the bridge, but perhaps if you can explain what you would have done we will be better able to understand your concerns.

I would ask that the bar for the "freeze()" feature include exceptions on modifications. If this is not feasible, the feature cannot be accepted.

The reason JS in 1995 had quirks such as silent failure on attempt to assign to a non-writable property was lack of try-catch. ES3 added try-catch, so you have a point: ES5 could have made attempting to extend a non-extensible object always throw, irrespective of whether the attempt was from strict mode code.

However, in that case attempts to assign to non-writable existing properties on a non-extensible object (frozen object) would still not throw when made from non-strict code, unless ES5 changed the logic for assignment to an existing property to check both [[Extensible]] and [[Writable]]. If I can even try to recall those days, this seemed inconsistent and illogical. Why should assignment

obj.foo = 42;

fail with a thrown exception for obj = Object.freeze({}) and obj = Object.freeze({foo:0}) but not for obj = {}; Object.defineProperty(obj, 'foo', {value:0})? All three ways of creating obj should either throw on the obj.foo = 42 attempt, or not throw.

So the heavy hand of pre-ES3 (pre-try-catch) primeval JS still hangs over the language.

I don't think this is as bad as you seem to think it is. Why not always "use strict"; at the top of your code, live long, and prosper?

# John J Barton (12 years ago)

On Mon, May 28, 2012 at 11:23 PM, Brendan Eich <brendan at mozilla.org> wrote:

John J Barton wrote:

On Mon, May 28, 2012 at 10:09 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>  wrote:

On May 28, 2012, at 10:03 PM, John J Barton wrote:

So let's rewind to my original question.  If the discussion about SES is leading us toward more things like freeze(), let's do a better job this time.

John, could you xplain what you would have done differently with "freeze()".  It's water under the bridge, but perhaps if you can explain what you would have done we will be better able to understand your concerns.

I would ask that the bar for the "freeze()" feature include exceptions on modifications. If this is not feasible, the feature cannot be accepted.

The reason JS in 1995 had quirks such as silent failure on attempt to assign to a non-writable property was lack of try-catch. ES3 added try-catch, so you have a point: ES5 could have made attempting to extend a non-extensible object always throw, irrespective of whether the attempt was from strict mode code.

However, in that case attempts to assign to non-writable existing properties on a non-extensible object (frozen object) would still not throw when made from non-strict code, unless ES5 changed the logic for assignment to an existing property to check both [[Extensible]] and [[Writable]]. If I can even try to recall those days, this seemed inconsistent and illogical. Why should assignment

obj.foo = 42;

fail with a thrown exception for obj = Object.freeze({}) and obj = Object.freeze({foo:0}) but not for obj = {}; Object.defineProperty(obj, 'foo', {value:0})? All three ways of creating obj should either throw on the obj.foo = 42 attempt, or not throw.

So the heavy hand of pre-ES3 (pre-try-catch) primeval JS still hangs over the language.

Thanks for the explanation.

I don't think this is as bad as you seem to think it is.

This is one of those cases where a small delta creates a very large negative effect.

Why not always "use strict"; at the top of your code, live long, and prosper?

  1. The advertised advantages of "use strict" (developer.mozilla.org/en/JavaScript/Strict_mode) seem very minor to me. I've never had any of the problems it solves and -- until recently -- I've never encountered freeze in real code.
  2. I had legacy code using "with".
  3. Inertia.

In my experience jslint is a much more powerful as a development aid than 'use strict'. Surprisingly there are still developers who don't use such tools. I guess they have a similar list to mine above.

I hope the coming generation of development tools will expand to include dynamic error analysis that won't need to live within the ES limitations of compatibility.

jjb

# Jussi Kalliokoski (12 years ago)

I just wanted to add more weight to the fact that frozen objects aren't really the only objects you can't write to; it's the same with primitives (string, number, etc) as well, and all of them fail silently, it's very JSy to fail silently on write:

var a = 1; a.x = 2; console.log(a.x); // undefined

# Brendan Eich (12 years ago)

Jussi Kalliokoski wrote:

I just wanted to add more weight to the fact that frozen objects aren't really the only objects you can't write to; it's the same with primitives (string, number, etc) as well, and all of them fail silently, it's very JSy to fail silently on write:

var a = 1; a.x = 2; console.log(a.x); // undefined

This is not a case where strict mode would throw:

js> "use strict"; var a = 1; a.x = 2

2 js> a.x

This shows ephemeral object wrappers being "created" (most engines optimize them away, mostly) for primitive values.

# T.J. Crowder (12 years ago)

On 29 May 2012 19:26, Jussi Kalliokoski <jussi.kalliokoski at gmail.com> wrote:

I just wanted to add more weight to the fact that frozen objects aren't really the only objects you can't write to; it's the same with primitives (string, number, etc) as well, and all of them fail silently, it's very JSy to fail silently on write:

var a = 1; a.x = 2; console.log(a.x); // undefined

Well, the write didn't fail. It worked. It's just that you wrote to a temporary Number object that you didn't keep a reference to.

a.x = 2;

...creates a temporary Number and throws it away.

console.log(a.x);

...creates a different temporary Number, which has no x property.

Not the same thing. :-)

-- T.J.

# Brendan Eich (12 years ago)

John J Barton wrote:

This is one of those cases where a small delta creates a very large negative effect.

Evidence?

# John Tamplin (12 years ago)

On Tue, May 29, 2012 at 1:15 PM, John J Barton <johnjbarton at johnjbarton.com>wrote:

  1. The advertised advantages of "use strict" (developer.mozilla.org/en/JavaScript/Strict_mode) seem very minor to me. I've never had any of the problems it solves and -- until recently -- I've never encountered freeze in real code.

If silent failures on writing to a frozen object are as much a concern to you as you suggest, then that sounds like reason enough. If they aren't that much of a problem, then why do you care about the issue enough to break backwards compatibility for those that do care?

  1. I had legacy code using "with".

You probably want to rewrite such code even if you aren't using SES -- check out the performance implications.

# Brendan Eich (12 years ago)

John Tamplin wrote:

# Anton Kovalyov (12 years ago)

FWIW I don't think it's even possible to use JSLint and 'with'. The parser just quits as if it was a syntax error.

Anton

# John J Barton (12 years ago)

On Tue, May 29, 2012 at 11:32 AM, Brendan Eich <brendan at mozilla.org> wrote:

John J Barton wrote:

This is one of those cases where a small delta creates a very large negative effect.

Evidence?

If you look back on this thread you will see an example extracted from the case that caused me pain. In the real life case I was using Kris Kowal's Q_COMM library, which builds on Q and is quite sophisticated code.

I added a function to a Q_COMM object. Later when I called the function I got an error. I had no idea that 'freeze' was involved. I was mystified.

For debugging I added a call as well as various tests for the function existence immediately after I added the function. Then I wasted a lot of time trying to create a test case to show the browser team that they had a bug. Since I could not reproduce the problem I stepped through Q_COMM code. Eventually I found this line var defend = Object.freeze || noop;

Anytime you have to debug library code it's a big negative effect. Is there a way to debug this which is simple, given no strict nor previous knowledge of freeze?

Devtools could have marked the object as froze, code.google.com/p/chromium/issues/detail?id=130127

jjb

# Jussi Kalliokoski (12 years ago)

Re: strict mode not throwing in this case, yeah, I'm aware, I was just showing how it is not un-JSy for defining properties to fail.

On Tue, May 29, 2012 at 9:30 PM, T.J. Crowder <tj at crowdersoftware.com>wrote:

On 29 May 2012 19:26, Jussi Kalliokoski <jussi.kalliokoski at gmail.com>wrote:

I just wanted to add more weight to the fact that frozen objects aren't really the only objects you can't write to; it's the same with primitives (string, number, etc) as well, and all of them fail silently, it's very JSy to fail silently on write:

var a = 1; a.x = 2; console.log(a.x); // undefined

Well, the write didn't fail. It worked. It's just that you wrote to a temporary Number object that you didn't keep a reference to.

a.x = 2;

...creates a temporary Number and throws it away.

console.log(a.x);

...creates a different temporary Number, which has no x property.

Not the same thing. :-)

-- T.J.

Yes, sorry, I was simplifying a bit, but still, from the program's perspective, defining the property x of a failed, silently. :)

# John J Barton (12 years ago)

On Tue, May 29, 2012 at 12:08 PM, Anton Kovalyov <ml at kovalyov.net> wrote:

FWIW I don't think it's even possible to use JSLint and 'with'. The parser just quits as if it was a syntax error.

Yes this is correct.

Anton

On Tuesday, May 29, 2012 at 11:40 AM, Brendan Eich wrote:

John Tamplin wrote:

  1. I had legacy code using "with".

You probably want to rewrite such code even if you aren't using SES -- check out the performance implications.

I seriously doubt such a change would have any measurable effect. Or rather: there are so many better ways to improved this code.

And JSLint won't let you use 'with', not even with options (IIRC).

John, do you really use JSLint and 'with'? Paging Dr. Crockford! ;-)

I'll not make any claims that jslint is perfect. But when it fails you just ignore it.

jjb

# Brendan Eich (12 years ago)

John J Barton wrote:

Anytime you have to debug library code it's a big negative effect.

I agree in general. I also see most developers have to do this, some of the time. Modularity is never "done" enough in practice to save us from this, in JS, C/C++, other languages.

Is there a way to debug this which is simple, given no strict nor previous knowledge of freeze?

Trying to set something and seeing the assignment fail? It's a drag. Object.isFrozen can help but you have to know to use it.

Devtools could have marked the object as froze, code.google.com/p/chromium/issues/detail?id=130127

Cool, good idea.

# Claus Reinke (12 years ago)

If you look back on this thread you will see an example extracted from the case that caused me pain. In the real life case I was using Kris Kowal's Q_COMM library, which builds on Q and is quite sophisticated code.

I added a function to a Q_COMM object. Later when I called the function I got an error. I had no idea that 'freeze' was involved. I was mystified.

Was that addition in a function that could have profited from a local "use strict"? How costly would it have been to remove sufficiently many non-strict features in order to profit from strict checks?

Devtools could have marked the object as froze, code.google.com/p/chromium/issues/detail?id=130127

Btw, are all browser's devtools developers listening here, or on js-tools[1], or on some other list? Or are the individual bug trackers the only way to reach them all with useful suggestions such as this one?

Claus

[1] groups.google.com/group/js-tools/about

# John J Barton (12 years ago)

On Tue, May 29, 2012 at 2:47 PM, Claus Reinke <claus.reinke at talk21.com> wrote:

If you look back on this thread you will see an example extracted from the case that caused me pain. In the real life case I was using Kris Kowal's Q_COMM library, which builds on Q and is quite sophisticated code.

I added a function to a Q_COMM object. Later when I called the function I got an error. I had no idea that 'freeze' was involved.  I was mystified.

Was that addition in a function that could have profited from a local "use strict"? How costly would it have been to remove sufficiently many non-strict features in order to profit from strict checks?

I guess you are asking: "Could I have issued "use strict" in the Q_COMM related code but not in the "with" related code? Yes of course.

Devtools could have marked the object as froze, code.google.com/p/chromium/issues/detail?id=130127

Btw, are all browser's devtools developers listening here, or on js-tools[1], or on some other list? Or are the individual bug trackers the only way to reach them all with useful suggestions such as this one?

I don't know the answer to these questions. I can tell you that clear bug reports with simple test cases are necessary but not sufficient. Personally I'm interested in lowering the bar for contributions to developer tools via eg extensions.

jjb

# David Bruant (12 years ago)

Le 29/05/2012 21:18, John J Barton a écrit :

On Tue, May 29, 2012 at 11:32 AM, Brendan Eich<brendan at mozilla.org> wrote:

John J Barton wrote:

This is one of those cases where a small delta creates a very large negative effect.

Evidence? If you look back on this thread you will see an example extracted from the case that caused me pain. In the real life case I was using Kris Kowal's Q_COMM library, which builds on Q and is quite sophisticated code.

I added a function to a Q_COMM object. Later when I called the function I got an error. I had no idea that 'freeze' was involved. I was mystified.

For debugging I added a call as well as various tests for the function existence immediately after I added the function. Then I wasted a lot of time trying to create a test case to show the browser team that they had a bug. Since I could not reproduce the problem I stepped through Q_COMM code. Eventually I found this line var defend = Object.freeze || noop;

Anytime you have to debug library code it's a big negative effect. Is there a way to debug this which is simple, given no strict nor previous knowledge of freeze?

As Brendan said, Object.isFrozen (or just Object.isExtensible) can do the trick.

Devtools could have marked the object as froze, code.google.com/p/chromium/issues/detail?id=130127

Devtools really are not ready for ES5 yet unfortunately. I've made a tool that visualize an object (then its prototype, then its prototype, etc.): davidbruant.github.com/ObjectViz You can visualize any object by going to the JavaScript console and typing 'ObjectViz(yourObject)'. There is no legend, but color is for value type (white is getters/setters which are not called). There are visual codes for non-configurable, non-writable or non-enumerable properties as well as non-extensible properties. I've had a lot of feedback of people telling me it could be useful as a debugging tool. Currently, it takes way too much space and the code isn't packaged for that yet, but the idea is here.

# John J Barton (12 years ago)

On Wed, May 30, 2012 at 12:45 AM, David Bruant <bruant.d at gmail.com> wrote:

Le 29/05/2012 21:18, John J Barton a écrit :

On Tue, May 29, 2012 at 11:32 AM, Brendan Eich<brendan at mozilla.org>  wrote:

John J Barton wrote:

This is one of those cases where a small delta creates a very large negative effect.

Evidence?

If you look back on this thread you will see an example extracted from the case that caused me pain. In the real life case I was using Kris Kowal's Q_COMM library, which builds on Q and is quite sophisticated code.

I added a function to a Q_COMM object. Later when I called the function I got an error. I had no idea that 'freeze' was involved.  I was mystified.

For debugging I added a call as well as various tests for the function existence immediately after I added the function. Then I wasted a lot of time trying to create a test case to show the browser team that they had a bug. Since I could not reproduce the problem I stepped through Q_COMM code. Eventually I found this line   var defend = Object.freeze || noop;

Anytime you have to debug library code it's a big negative effect.  Is there a way to debug this which is simple, given no strict nor previous knowledge of freeze?

As Brendan said, Object.isFrozen (or just Object.isExtensible) can do the trick.

This assumes the developer expects a frozen object. Like I said, this was the first time I encountered one.

Devtools could have marked the object as froze, code.google.com/p/chromium/issues/detail?id=130127

Devtools really are not ready for ES5 yet unfortunately.

Let me use this comment to follow up on Claus' post as well.

In my experience additions to development tools come from three forces:

  1. Personal interests. For example that is why I worked on eval debugging and graphical breakpoints.
  2. Developer requests (newsgroups, bug reports, developer relations, blogs, etc). For example that is how we got many of the features in the Net panel of Firebug and Devtools.
  3. Organizational requests. For example, Google's large web apps lead to better memory analysis tools.

I'm not sure which features you are missing but (again in my experience) the existence of a feature in the standard doesn't cause devtools support absent one of the forces above.

I've made a tool that visualize an object (then its prototype, then its prototype, etc.): davidbruant.github.com/ObjectViz You can visualize any object by going to the JavaScript console and typing 'ObjectViz(yourObject)'. There is no legend, but color is for value type (white is getters/setters which are not called). There are visual codes for non-configurable, non-writable or non-enumerable properties as well as non-extensible properties. I've had a lot of feedback of people telling me it could be useful as a debugging tool. Currently, it takes way too much space and the code isn't packaged for that yet, but the idea is here.

Chrome devtools has a good start on extensibility and this is area we are expanding. Reach out on the devtools or jstools newsgroup if you want help embedding ObjectViz.

jjb

# Brandon Benvie (12 years ago)

I would say this is one of the places that Node shines, due to providing very easy to use access to the C++ API of V8 directly as JS modules. Straight copying and pasting from v8.h to a module that directly exposes the functions to JS can provide access to most of the tools one would want from JS that are out of JSland's reach normally. I slapped this together while playing around with it the other day gist.github.com/2837880.