Object.seal, read references, and code reliability

classic Classic list List threaded Threaded
32 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Object.seal, read references, and code reliability

Alex Kodat

I’m sure this has been brought up before but my naïve searches come up empty handed so…

 

Is there any reason that there’s no flavor of Object.seal that would throw an exception on read references to properties that are not found on the specified object? While this could be accomplished with an extra parameter on seal, for the save of this discussion I’ll call it a different function: Object.lock.

 

We’ve found Object.seal to be a huge aid in improving programmer productivity by catching coding errors early and preventing people from intentionally or unintentionally adding properties to objects outside the constructor. Our constructors typically add all the properties to an object and then seal it. This ensures that there’s one place to see all the properties for an object and the extra cost of adding perhaps seldom used properties is won back because the shape of the object is guaranteed not to change after the constructor playing very nicely with V8 optimizations though presumably other engines would also benefit. While, of course, there are objects that don’t fit this static-ish model, the bulk of them do and for those, this approach is a huge win for code maintainability.

 

But, what still bites frequently is read references to non-existent properties which are returned as undefined. Quite often, this results in a quick exception when the undefined is used as a this and sometimes the problem is exposed as a NaN or the string “undefined” appearing in text or whatever, at which point one must backtrack to the source of the problem. The worst is when the property is used as a Boolean and undefined simply behaves as false. While I’m sure there are cases where this behavior is useful, we certainly haven’t run across them and the fact that Object.seal doesn’t protect against reads of non-existent properties is a complete negative. But, of course, backward-compatibility means Object.seal cannot do this.

 

My guess is that the difficulty would lie in the prototype chain where the runtime wouldn’t know that the property doesn’t exist until it’s at the end of the prototype chain at which point it might not have a reference to the original object. Even worse, an Object.lock might have locked some intermediate object in the prototype chain which presumably should cause an exception on a non-existent property reference. Essentially an Object.lock on any object in the prototype chain should act as a barrier to the return of undefined for non-existent properties.

 

This would suggest an implementation where before going down the prototype chain the JS runtime would OR the lock bit in the current object with a running lock barrier bit. If it hits the end of the prototype chain and the property has not been found and the lock barrier bit is set, exception. Of course, this would add at least one extra OR for *every* prototype chain step but that doesn’t seem too horrible and certainly for something like V8 with its underlying object Maps this would essentially add no overhead for the vast majority of property retrievals.

 

And yes, this can be accomplished with a simple generic proxy but that seems like a heavyweight solution to the problem.

 

------

Alex Kodat
Senior Product Architect
Rocket Software
t: +1 781 684 2294 • m: +1 315 527 4764 • w: www.rocketsoftware.com

 

================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: +1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Object.seal, read references, and code reliability

T.J. Crowder-2
On Mon, Aug 14, 2017 at 5:32 PM, Alex Kodat <[hidden email]> wrote:
> Is there any reason that there’s no flavor of Object.seal that
> would throw an exception on read references to properties that are
> not found on the specified object?

This sounds like a good idea at a high level. Will be very interested to know what implementers have to say about it from an implementation perspective.

In spec terms, at first glance it's mostly just a new pair of steps in [OrdinaryGet ordinary object internal function][1] (added Step 3.a and 3.b):

```text
1. Assert: IsPropertyKey(P) is true.
2. Let desc be ? O.[[GetOwnProperty]](P).
3. If desc is undefined, then
 a. Let readExtendable be ? IsReadExtensible(Receiver).
 b. If readExtendable is false, throw TypeError.
 c. Let parent be ? O.[[GetPrototypeOf]]().
 d. If parent is null, return undefined.
 e. Return ? parent.[[Get]](P, Receiver).
4. If IsDataDescriptor(desc) is true, return desc.[[Value]].
5. Assert: IsAccessorDescriptor(desc) is true.
6. Let getter be desc.[[Get]].
7. If getter is undefined, return undefined.
8. Return ? Call(getter, Receiver).
```

...where `IsReadExtensible` is an op to test the new flag. *(Used `pre` markdown to avoid the `[[...](.)` being treated as links without having to add `\` for those not reading the rendered version.)*

One concern is people already have trouble keeping sealed and frozen straight (or is that just me?). Adding a locked (or whatever) makes that even more confusing. But the semantics of sealed and frozen can't be changed to include this now.

-- T.J. Crowder


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

RE: Object.seal, read references, and code reliability

Alex Kodat

FWIW, I’m not sure I agree with your OrdinaryGet steps. Also, not sure I like readExtensible as it doesn’t really have anything to do with extensibility. Maybe readStrict? But maybe I’m thinking about extensibility wrong?

 

In any case, I think the description of [[Get]] would have to be like (sorry, I’ve never done this sort of spec pseudo code so some of this is probably syntactically incorrect):

 

[[Get]] (P, Receiver, ReadStrict)

  1. Return ? OrdinaryGet(O, P, Receiver, ReadStrict).

 

And OrdinaryGet would be like:

 

OrdinaryGet (O, P, Receiver, ReadStrict)#

  1. Assert: IsPropertyKey(P) is true.
  2. Let desc be ? O.[[GetOwnProperty]](P).
  3. If desc is undefined, then
  1. Let readStrict be ? O.IsReadStrict(Receiver) || ReadStrict
  2. Let parent be ? O.[[GetPrototypeOf]]().
  3. If parent is null then

i.                     Assert: readStrict is false

ii.                    return undefined.

  1. Return ? parent.[[Get]](P, Receiver, readStrict).
  1. If IsDataDescriptor(desc) is true, return desc.[[Value]].
  2. Assert: IsAccessorDescriptor(desc) is true.
  3. Let getter be desc.[[Get]].
  4. If getter is undefined, return undefined.
  5. Return ? Call(getter, Receiver).

 

Probably adjustments need to be made to other references to [[Get]] and OrdinaryGet, passing false for ReadStrict.

 

I guess this pseudo code also points out an issue as to whether Object.lock would affect a dynamic property with no getter. Intuitively, it seems to me that it should.

 

------

Alex Kodat
Senior Product Architect
Rocket Software
t: +1 781 684 2294 • m: +1 315 527 4764 • w: www.rocketsoftware.com

 

From: T.J. Crowder [mailto:[hidden email]]
Sent: Monday, August 14, 2017 12:00 PM
To: Alex Kodat <[hidden email]>
Cc: [hidden email]
Subject: Re: Object.seal, read references, and code reliability

 

On Mon, Aug 14, 2017 at 5:32 PM, Alex Kodat <[hidden email]> wrote:

> Is there any reason that there’s no flavor of Object.seal that

> would throw an exception on read references to properties that are

> not found on the specified object?

 

This sounds like a good idea at a high level. Will be very interested to know what implementers have to say about it from an implementation perspective.

 

In spec terms, at first glance it's mostly just a new pair of steps in [OrdinaryGet ordinary object internal function][1] (added Step 3.a and 3.b):

 

```text

1. Assert: IsPropertyKey(P) is true.

2. Let desc be ? O.[[GetOwnProperty]](P).

3. If desc is undefined, then

 a. Let readExtendable be ? IsReadExtensible(Receiver).

 b. If readExtendable is false, throw TypeError.

 c. Let parent be ? O.[[GetPrototypeOf]]().

 d. If parent is null, return undefined.

 e. Return ? parent.[[Get]](P, Receiver).

4. If IsDataDescriptor(desc) is true, return desc.[[Value]].

5. Assert: IsAccessorDescriptor(desc) is true.

6. Let getter be desc.[[Get]].

7. If getter is undefined, return undefined.

8. Return ? Call(getter, Receiver).

```

 

...where `IsReadExtensible` is an op to test the new flag. *(Used `pre` markdown to avoid the `[[...](.)` being treated as links without having to add `\` for those not reading the rendered version.)*

 

One concern is people already have trouble keeping sealed and frozen straight (or is that just me?). Adding a locked (or whatever) makes that even more confusing. But the semantics of sealed and frozen can't be changed to include this now.

 

-- T.J. Crowder

 

================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: +1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Object.seal, read references, and code reliability

T.J. Crowder-2
On Mon, Aug 14, 2017 at 7:16 PM, Alex Kodat <[hidden email]> wrote:
>
> FWIW, I’m not sure I agree with your OrdinaryGet steps.

Why not? (Not that spec language is important at this stage.)

> Also, not sure I like readExtensible as it doesn’t really have
> anything to do with extensibility.

That's fine, it was just a placeholder variable name in an internal method. :-) `"sealed"` and `"frozen"` are referred to with that terminology, and this is in the same general area although it isn't literally extensibility.

> In any case, I think the description of [[Get]] would have to be
> like...

Why do you think `[[Get]]` needs a flag? The object will have the flag on it, and `[[Get]]` has the object.

`OrdinaryGet` certainly doesn't need the flag. It has the object, and it has the relevant object at each stage in the prototype chain (note that it's indirectly recursive via `[[Get]]`).

Again, though, spec language isn't important at this stage. It's a good idea and I'd love to see it get legs.

-- T.J. Crowder


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Object.seal, read references, and code reliability

Oriol _
> Why do you think `[[Get]]` needs a flag? The object will have the flag on it, and `[[Get]]` has the object.

I also think a new flag or something similar is needed, because it would be good to throw if some object in the prototype chain is locked, not necessarily the receiver.
I would expect this:

```js
let locked = Object.lock({});
let inherits = Object.create(locked);
Reflect.get(locked, "foo"); // TypeError
Reflect.get(locked, "foo", {}); // TypeError
Reflect.get({}, "foo", locked); // undefined
Reflect.get(inherits, "foo"); // TypeError
```

-Oriol


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Object.seal, read references, and code reliability

Don Griffin
<imho>Land mines like this are bad for JS. Reads should always be safe to do as in "foo && foo.bar". Throwing errors from that is always bad. duck-typing, feature detection etc are all valid uses for objects ... even sealed/frozen/locked/obfuscated ones :) </imho>

Just give me "undefined" on reads like these. I would much rather have that and possibly Object.isFrozen/isLocked/isSealed etc methods to test these conditions if appropriate.


Best,
Don
--
Don Griffin
Sr Director of Engineering
Sencha, Inc.

On Mon, Aug 14, 2017 at 1:44 PM, Oriol _ <[hidden email]> wrote:
> Why do you think `[[Get]]` needs a flag? The object will have the flag on it, and `[[Get]]` has the object.

I also think a new flag or something similar is needed, because it would be good to throw if some object in the prototype chain is locked, not necessarily the receiver.
I would expect this:

```js
let locked = Object.lock({});
let inherits = Object.create(locked);
Reflect.get(locked, "foo"); // TypeError
Reflect.get(locked, "foo", {}); // TypeError
Reflect.get({}, "foo", locked); // undefined
Reflect.get(inherits, "foo"); // TypeError
```

-Oriol


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Object.seal, read references, and code reliability

T.J. Crowder-2
In reply to this post by T.J. Crowder-2
On Mon, Aug 14, 2017 at 7:24 PM, T.J. Crowder <[hidden email]> wrote:
>
> On Mon, Aug 14, 2017 at 7:16 PM, Alex Kodat <[hidden email]> wrote:
> >
> > FWIW, I’m not sure I agree with your OrdinaryGet steps.
>
> Why not? (Not that spec language is important at this stage.)

Ignore me, sorry. Appear to have left brain at office.

-- T.J. Crowder 

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: RE: Object.seal, read references, and code reliability

Jerry Schulteis
In reply to this post by Alex Kodat
I'm ok with the basic idea. I don't think "lock" is a good name for it. Nothing about "Object.lock(myObj)" suggests that future access to a non-existent property of myObj will throw. Also "lock" carries a well-established, unrelated meaning in computer science.

Could this be done with an additional argument to Object.seal(), Object.freeze(), and Object.preventExtensions()?
Like so: "Object.seal(myObj, Object.THROW_ON_ABSENT_PROPERTY_READ)"--wordy, but the intent is unmistakable.
On Monday, August 14, 2017, 1:16:39 PM CDT, Alex Kodat <[hidden email]> wrote:


FWIW, I’m not sure I agree with your OrdinaryGet steps. Also, not sure I like readExtensible as it doesn’t really have anything to do with extensibility. Maybe readStrict? But maybe I’m thinking about extensibility wrong?

 

In any case, I think the description of [[Get]] would have to be like (sorry, I’ve never done this sort of spec pseudo code so some of this is probably syntactically incorrect):

 

[[Get]] (P, Receiver, ReadStrict)

  1. Return ? OrdinaryGet(O, P, Receiver, ReadStrict).

 

And OrdinaryGet would be like:

 

OrdinaryGet (O, P, Receiver, ReadStrict)#

  1. Assert: IsPropertyKey(P) is true.
  2. Let desc be ? O.[[GetOwnProperty]](P).
  3. If desc is undefined, then
  1. Let readStrict be ? O.IsReadStrict(Receiver) || ReadStrict
  2. Let parent be ? O.[[GetPrototypeOf]]().
  3. If parent is null then

i.                     Assert: readStrict is false

ii.                    return undefined.

  1. Return ? parent.[[Get]](P, Receiver, readStrict).
  1. If IsDataDescriptor(desc) is true, return desc.[[Value]].
  2. Assert: IsAccessorDescriptor(desc) is true.
  3. Let getter be desc.[[Get]].
  4. If getter is undefined, return undefined.
  5. Return ? Call(getter, Receiver).

 

Probably adjustments need to be made to other references to [[Get]] and OrdinaryGet, passing false for ReadStrict.

 

I guess this pseudo code also points out an issue as to whether Object.lock would affect a dynamic property with no getter. Intuitively, it seems to me that it should.

 

------

Alex Kodat
Senior Product Architect
Rocket Software
t: +1 781 684 2294 • m: +1 315 527 4764 • w: www.rocketsoftware.com

 

From: T.J. Crowder [mailto:[hidden email]]
Sent: Monday, August 14, 2017 12:00 PM
To: Alex Kodat <[hidden email]>
Cc: [hidden email]
Subject: Re: Object.seal, read references, and code reliability

 

On Mon, Aug 14, 2017 at 5:32 PM, Alex Kodat <[hidden email]> wrote:

> Is there any reason that there’s no flavor of Object.seal that

> would throw an exception on read references to properties that are

> not found on the specified object?

 

This sounds like a good idea at a high level. Will be very interested to know what implementers have to say about it from an implementation perspective.

 

In spec terms, at first glance it's mostly just a new pair of steps in [OrdinaryGet ordinary object internal function][1] (added Step 3.a and 3.b):

 

```text

1. Assert: IsPropertyKey(P) is true.

2. Let desc be ? O.[[GetOwnProperty]](P).

3. If desc is undefined, then

 a. Let readExtendable be ? IsReadExtensible(Receiver).

 b. If readExtendable is false, throw TypeError.

 c. Let parent be ? O.[[GetPrototypeOf]]().

 d. If parent is null, return undefined.

 e. Return ? parent.[[Get]](P, Receiver).

4. If IsDataDescriptor(desc) is true, return desc.[[Value]].

5. Assert: IsAccessorDescriptor(desc) is true.

6. Let getter be desc.[[Get]].

7. If getter is undefined, return undefined.

8. Return ? Call(getter, Receiver).

```

 

...where `IsReadExtensible` is an op to test the new flag. *(Used `pre` markdown to avoid the `[[...](.)` being treated as links without having to add `\` for those not reading the rendered version.)*

 

One concern is people already have trouble keeping sealed and frozen straight (or is that just me?). Adding a locked (or whatever) makes that even more confusing. But the semantics of sealed and frozen can't be changed to include this now.

 

-- T.J. Crowder

 

================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: +1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

RE: RE: Object.seal, read references, and code reliability

Alex Kodat

Agree, lock’s not a good name. That was just a dumb name because I was too lazy to think of something better. Other names that come to mind (some also with other software connotations):

 

Object.box

Object.protect

Object.close

Object.guard

Object.fence

Object.shield

 

But don’t care that much and probably someone could come up with better. I guess of the above I like Object.guard. So I’ll use that for now…

 

Also, I’ll retract an earlier stupid statement I made where I suggested that if a property referenced an accessor descriptor without a getter it should throw if the guard bit is set. This is obviously wrong. As long as the property name is present, not having a getter is equivalent to the property being explicitly set to undefined which should not throw. That is:

 

let foo = Object.guard({a: 1, b: undefined});

console.log(foo.b);

 

should not throw.

 

Also, FWIW, I had originally thought of Object.guard as Object.seal on steroids but some thought makes me realize it’s really orthogonal and can picture cases where one might want to seal an object but not guard it and vice versa.

 

------

Alex Kodat
Senior Product Architect
Rocket Software
t: +1 781 684 2294 • m: +1 315 527 4764 • w: www.rocketsoftware.com

 

From: Jerry Schulteis [mailto:[hidden email]]
Sent: Monday, August 14, 2017 5:21 PM
To: Alex Kodat <[hidden email]>
Cc: [hidden email]
Subject: Re: RE: Object.seal, read references, and code reliability

 

I'm ok with the basic idea. I don't think "lock" is a good name for it. Nothing about "Object.lock(myObj)" suggests that future access to a non-existent property of myObj will throw. Also "lock" carries a well-established, unrelated meaning in computer science.

 

Could this be done with an additional argument to Object.seal(), Object.freeze(), and Object.preventExtensions()?

Like so: "Object.seal(myObj, Object.THROW_ON_ABSENT_PROPERTY_READ)"--wordy, but the intent is unmistakable.

On Monday, August 14, 2017, 1:16:39 PM CDT, Alex Kodat <[hidden email]> wrote:

 

 

FWIW, I’m not sure I agree with your OrdinaryGet steps. Also, not sure I like readExtensible as it doesn’t really have anything to do with extensibility. Maybe readStrict? But maybe I’m thinking about extensibility wrong?

 

In any case, I think the description of [[Get]] would have to be like (sorry, I’ve never done this sort of spec pseudo code so some of this is probably syntactically incorrect):

 

[[Get]] (P, Receiver, ReadStrict)

  1. Return ? OrdinaryGet(O, P, Receiver, ReadStrict).

 

And OrdinaryGet would be like:

 

OrdinaryGet (O, P, Receiver, ReadStrict)#

  1. Assert: IsPropertyKey(P) is true.
  2. Let desc be ? O.[[GetOwnProperty]](P).
  3. If desc is undefined, then
  1. Let readStrict be ? O.IsReadStrict(Receiver) || ReadStrict
  2. Let parent be ? O.[[GetPrototypeOf]]().
  3. If parent is null then

i.                     Assert: readStrict is false

ii.                    return undefined.

  1. Return ? parent.[[Get]](P, Receiver, readStrict).
  1. If IsDataDescriptor(desc) is true, return desc.[[Value]].
  2. Assert: IsAccessorDescriptor(desc) is true.
  3. Let getter be desc.[[Get]].
  4. If getter is undefined, return undefined.
  5. Return ? Call(getter, Receiver).

 

Probably adjustments need to be made to other references to [[Get]] and OrdinaryGet, passing false for ReadStrict.

 

I guess this pseudo code also points out an issue as to whether Object.lock would affect a dynamic property with no getter. Intuitively, it seems to me that it should.

 

------

Alex Kodat
Senior Product Architect
Rocket Software
t: +1 781 684 2294 • m: +1 315 527 4764 • w: www.rocketsoftware.com

 

From: T.J. Crowder [[hidden email]]
Sent: Monday, August 14, 2017 12:00 PM
To: Alex Kodat <[hidden email]>
Cc: [hidden email]
Subject: Re: Object.seal, read references, and code reliability

 

On Mon, Aug 14, 2017 at 5:32 PM, Alex Kodat <[hidden email]> wrote:

> Is there any reason that there’s no flavor of Object.seal that

> would throw an exception on read references to properties that are

> not found on the specified object?

 

This sounds like a good idea at a high level. Will be very interested to know what implementers have to say about it from an implementation perspective.

 

In spec terms, at first glance it's mostly just a new pair of steps in [OrdinaryGet ordinary object internal function][1] (added Step 3.a and 3.b):

 

```text

1. Assert: IsPropertyKey(P) is true.

2. Let desc be ? O.[[GetOwnProperty]](P).

3. If desc is undefined, then

 a. Let readExtendable be ? IsReadExtensible(Receiver).

 b. If readExtendable is false, throw TypeError.

 c. Let parent be ? O.[[GetPrototypeOf]]().

 d. If parent is null, return undefined.

 e. Return ? parent.[[Get]](P, Receiver).

4. If IsDataDescriptor(desc) is true, return desc.[[Value]].

5. Assert: IsAccessorDescriptor(desc) is true.

6. Let getter be desc.[[Get]].

7. If getter is undefined, return undefined.

8. Return ? Call(getter, Receiver).

```

 

...where `IsReadExtensible` is an op to test the new flag. *(Used `pre` markdown to avoid the `[[...](.)` being treated as links without having to add `\` for those not reading the rendered version.)*

 

One concern is people already have trouble keeping sealed and frozen straight (or is that just me?). Adding a locked (or whatever) makes that even more confusing. But the semantics of sealed and frozen can't be changed to include this now.

 

-- T.J. Crowder

 

================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: +1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: +1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: RE: Object.seal, read references, and code reliability

Bob Myers
Is there some reason this is not just a compile-time type check?
Bob

On Tue, Aug 15, 2017 at 4:16 AM, Alex Kodat <[hidden email]> wrote:

Agree, lock’s not a good name. That was just a dumb name because I was too lazy to think of something better. Other names that come to mind (some also with other software connotations):

 

Object.box

Object.protect

Object.close

Object.guard

Object.fence

Object.shield

 

But don’t care that much and probably someone could come up with better. I guess of the above I like Object.guard. So I’ll use that for now…

 

Also, I’ll retract an earlier stupid statement I made where I suggested that if a property referenced an accessor descriptor without a getter it should throw if the guard bit is set. This is obviously wrong. As long as the property name is present, not having a getter is equivalent to the property being explicitly set to undefined which should not throw. That is:

 

let foo = Object.guard({a: 1, b: undefined});

console.log(foo.b);

 

should not throw.

 

Also, FWIW, I had originally thought of Object.guard as Object.seal on steroids but some thought makes me realize it’s really orthogonal and can picture cases where one might want to seal an object but not guard it and vice versa.

 

------

Alex Kodat
Senior Product Architect
Rocket Software
t: +1 781 684 2294 • m: +1 315 527 4764 • w: www.rocketsoftware.com

 

From: Jerry Schulteis [mailto:[hidden email]]
Sent: Monday, August 14, 2017 5:21 PM
To: Alex Kodat <[hidden email]>
Cc: [hidden email]
Subject: Re: RE: Object.seal, read references, and code reliability

 

I'm ok with the basic idea. I don't think "lock" is a good name for it. Nothing about "Object.lock(myObj)" suggests that future access to a non-existent property of myObj will throw. Also "lock" carries a well-established, unrelated meaning in computer science.

 

Could this be done with an additional argument to Object.seal(), Object.freeze(), and Object.preventExtensions()?

Like so: "Object.seal(myObj, Object.THROW_ON_ABSENT_PROPERTY_READ)"--wordy, but the intent is unmistakable.

On Monday, August 14, 2017, 1:16:39 PM CDT, Alex Kodat <[hidden email]> wrote:

 

 

FWIW, I’m not sure I agree with your OrdinaryGet steps. Also, not sure I like readExtensible as it doesn’t really have anything to do with extensibility. Maybe readStrict? But maybe I’m thinking about extensibility wrong?

 

In any case, I think the description of [[Get]] would have to be like (sorry, I’ve never done this sort of spec pseudo code so some of this is probably syntactically incorrect):

 

[[Get]] (P, Receiver, ReadStrict)

  1. Return ? OrdinaryGet(O, P, Receiver, ReadStrict).

 

And OrdinaryGet would be like:

 

OrdinaryGet (O, P, Receiver, ReadStrict)#

  1. Assert: IsPropertyKey(P) is true.
  2. Let desc be ? O.[[GetOwnProperty]](P).
  3. If desc is undefined, then
  1. Let readStrict be ? O.IsReadStrict(Receiver) || ReadStrict
  2. Let parent be ? O.[[GetPrototypeOf]]().
  3. If parent is null then

i.                     Assert: readStrict is false

ii.                    return undefined.

  1. Return ? parent.[[Get]](P, Receiver, readStrict).
  1. If IsDataDescriptor(desc) is true, return desc.[[Value]].
  2. Assert: IsAccessorDescriptor(desc) is true.
  3. Let getter be desc.[[Get]].
  4. If getter is undefined, return undefined.
  5. Return ? Call(getter, Receiver).

 

Probably adjustments need to be made to other references to [[Get]] and OrdinaryGet, passing false for ReadStrict.

 

I guess this pseudo code also points out an issue as to whether Object.lock would affect a dynamic property with no getter. Intuitively, it seems to me that it should.

 

------

Alex Kodat
Senior Product Architect
Rocket Software
t: +1 781 684 2294 • m: +1 315 527 4764 • w: www.rocketsoftware.com

 

From: T.J. Crowder [[hidden email]]
Sent: Monday, August 14, 2017 12:00 PM
To: Alex Kodat <[hidden email]>
Cc: [hidden email]
Subject: Re: Object.seal, read references, and code reliability

 

On Mon, Aug 14, 2017 at 5:32 PM, Alex Kodat <[hidden email]> wrote:

> Is there any reason that there’s no flavor of Object.seal that

> would throw an exception on read references to properties that are

> not found on the specified object?

 

This sounds like a good idea at a high level. Will be very interested to know what implementers have to say about it from an implementation perspective.

 

In spec terms, at first glance it's mostly just a new pair of steps in [OrdinaryGet ordinary object internal function][1] (added Step 3.a and 3.b):

 

```text

1. Assert: IsPropertyKey(P) is true.

2. Let desc be ? O.[[GetOwnProperty]](P).

3. If desc is undefined, then

 a. Let readExtendable be ? IsReadExtensible(Receiver).

 b. If readExtendable is false, throw TypeError.

 c. Let parent be ? O.[[GetPrototypeOf]]().

 d. If parent is null, return undefined.

 e. Return ? parent.[[Get]](P, Receiver).

4. If IsDataDescriptor(desc) is true, return desc.[[Value]].

5. Assert: IsAccessorDescriptor(desc) is true.

6. Let getter be desc.[[Get]].

7. If getter is undefined, return undefined.

8. Return ? Call(getter, Receiver).

```

 

...where `IsReadExtensible` is an op to test the new flag. *(Used `pre` markdown to avoid the `[[...](.)` being treated as links without having to add `\` for those not reading the rendered version.)*

 

One concern is people already have trouble keeping sealed and frozen straight (or is that just me?). Adding a locked (or whatever) makes that even more confusing. But the semantics of sealed and frozen can't be changed to include this now.

 

-- T.J. Crowder

 

================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: +1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: +1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

RE: Object.seal, read references, and code reliability

Alex Kodat
In reply to this post by T.J. Crowder-2
On Mon Aug 14 18:49:35 UTC 2017 Don Griffin wrote
------------------------------------------------------------------------------------
<imho>Land mines like this are bad for JS. Reads should always be safe to do as in "foo && foo.bar". Throwing errors from that is always bad. duck-typing, feature detection etc are all valid uses for objects ... even sealed/frozen/locked/obfuscated ones :) </imho>

Just give me "undefined" on reads like these. I would much rather have that and possibly Object.isFrozen/isLocked/isSealed etc methods to test these conditions if appropriate.
------------------------------------------------------------------------------------
No one would force anyone to use Object.guard (what I initially called Object.lock). It would introduce no backward incompatibilities.

Whatever landmines this feature would introduce have been there at least since proxies were introduced since, with proxies, a get for a non-existent property might throw. In fact, even with a simple property getter you can get an exception from a getter. So the good old days when reads were always safe was a very long time ago. Of course, in your own code, you can very easily make your reads always safe and I'd say more power to you.

Duck-typing, feature detection, etc. can be wonderful things but so can objects with a well-defined set of properties. And in the latter case, it makes debugging much easier and faster if references to non-existent properties throw an exception.

Even in the face of Object.guard, feature detection could be done with Object.getOwnPropertyNames and Object.getPrototypeOf or Object.prototype.hasOwnProperty (the latter if one doesn't care about properties in prototype classes). In fact, as a general rule doing a feature test as if (foo.feature) is kinda sketchy as, of course, if foo.feature were 0 or "" or false your test would suggest a missing feature. Even if foo.feature returned undefined you don't know whether the property's explicitly set to undefined or simply not there (shame on you if there's a difference?).

Your e-mail does point to one minor fly in the ointment for the proposed Object.guard function, specifically the toJSON function for which a [[Get]] will be performed for every object being JSON.stringify'ed. This means that every object that is Object.guard'ed would require a toJSON in its prototype chain. A little annoying but a price to pay, I guess for using Object.guard. One would probably need to do the same for inspect. Of course one can set toJSON and inspect to undefined on the base Object prototype but that would probably be pretty uncool for most JavaScript engines.  There'd be other ways around this such as redefining JSON.stringify's use of toJSON to check for presence of the toJSON property before doing a [[Get]]. This would be indistinguishable from current behavior. And though it might seem expensive, I suspect most of the time there will be no toJSON property for most objects so the test for the property existence would be all that would be done.

------
Alex Kodat
Senior Product Architect
Rocket Software
t: +1 781 684 2294 • m: +1 315 527 4764 • w: www.rocketsoftware.com

================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: +1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Object.seal, read references, and code reliability

Jordan Harband
Don't forget besides `.toJSON`, all the other methods that builtins do a [[Get]] on: `.toString`, `.valueOf`, `.then`, and all the well-known symbols (Symbol.iterator, Symbol.isConcatSpreadable, etc) - and in node, `.inspect` in the repl.

You're totally right that Proxy, and ES5 getters before that, makes "accessing a property" always be something that can throw - just pointing out that there's a *lot* of places that `[[Get]]`s happen in the language.

On Mon, Aug 14, 2017 at 9:57 PM, Alex Kodat <[hidden email]> wrote:
On Mon Aug 14 18:49:35 UTC 2017 Don Griffin wrote
------------------------------------------------------------------------------------
<imho>Land mines like this are bad for JS. Reads should always be safe to do as in "foo && foo.bar". Throwing errors from that is always bad. duck-typing, feature detection etc are all valid uses for objects ... even sealed/frozen/locked/obfuscated ones :) </imho>

Just give me "undefined" on reads like these. I would much rather have that and possibly Object.isFrozen/isLocked/isSealed etc methods to test these conditions if appropriate.
------------------------------------------------------------------------------------
No one would force anyone to use Object.guard (what I initially called Object.lock). It would introduce no backward incompatibilities.

Whatever landmines this feature would introduce have been there at least since proxies were introduced since, with proxies, a get for a non-existent property might throw. In fact, even with a simple property getter you can get an exception from a getter. So the good old days when reads were always safe was a very long time ago. Of course, in your own code, you can very easily make your reads always safe and I'd say more power to you.

Duck-typing, feature detection, etc. can be wonderful things but so can objects with a well-defined set of properties. And in the latter case, it makes debugging much easier and faster if references to non-existent properties throw an exception.

Even in the face of Object.guard, feature detection could be done with Object.getOwnPropertyNames and Object.getPrototypeOf or Object.prototype.hasOwnProperty (the latter if one doesn't care about properties in prototype classes). In fact, as a general rule doing a feature test as if (foo.feature) is kinda sketchy as, of course, if foo.feature were 0 or "" or false your test would suggest a missing feature. Even if foo.feature returned undefined you don't know whether the property's explicitly set to undefined or simply not there (shame on you if there's a difference?).

Your e-mail does point to one minor fly in the ointment for the proposed Object.guard function, specifically the toJSON function for which a [[Get]] will be performed for every object being JSON.stringify'ed. This means that every object that is Object.guard'ed would require a toJSON in its prototype chain. A little annoying but a price to pay, I guess for using Object.guard. One would probably need to do the same for inspect. Of course one can set toJSON and inspect to undefined on the base Object prototype but that would probably be pretty uncool for most JavaScript engines.  There'd be other ways around this such as redefining JSON.stringify's use of toJSON to check for presence of the toJSON property before doing a [[Get]]. This would be indistinguishable from current behavior. And though it might seem expensive, I suspect most of the time there will be no toJSON property for most objects so the test for the property existence would be all that would be done.

------
Alex Kodat
Senior Product Architect
Rocket Software
t: <a href="tel:%2B1%20781%20684%202294" value="+17816842294">+1 781 684 2294 • m: <a href="tel:%2B1%20315%20527%204764" value="+13155274764">+1 315 527 4764 • w: www.rocketsoftware.com

================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: <a href="tel:%2B1%20877.328.2932" value="+18773282932">+1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

RE: RE: Object.seal, read references, and code reliability

Alex Kodat
In reply to this post by Bob Myers
It's not a compile-time check because a compile-time check is impossible:

   function noname(foo) {
      let abc = foo.abc;
    }

How could the compiler possibly know whether abc exists on foo?

------
Alex Kodat
Senior Product Architect
Rocket Software
t: +1 781 684 2294 • m: +1 315 527 4764 • w: http://www.rocketsoftware.com/

From: Bob Myers [mailto:[hidden email]]
Sent: Monday, August 14, 2017 11:55 PM
To: Alex Kodat <[hidden email]>
Cc: Jerry Schulteis <[hidden email]>; [hidden email]
Subject: Re: RE: Object.seal, read references, and code reliability

Is there some reason this is not just a compile-time type check?
Bob

On Tue, Aug 15, 2017 at 4:16 AM, Alex Kodat <mailto:[hidden email]> wrote:
Agree, lock’s not a good name. That was just a dumb name because I was too lazy to think of something better. Other names that come to mind (some also with other software connotations):

Object.box
Object.protect
Object.close
Object.guard
Object.fence
Object.shield

But don’t care that much and probably someone could come up with better. I guess of the above I like Object.guard. So I’ll use that for now…

Also, I’ll retract an earlier stupid statement I made where I suggested that if a property referenced an accessor descriptor without a getter it should throw if the guard bit is set. This is obviously wrong. As long as the property name is present, not having a getter is equivalent to the property being explicitly set to undefined which should not throw. That is:

let foo = Object.guard({a: 1, b: undefined});
console.log(foo.b);

should not throw.

Also, FWIW, I had originally thought of Object.guard as Object.seal on steroids but some thought makes me realize it’s really orthogonal and can picture cases where one might want to seal an object but not guard it and vice versa.

------
Alex Kodat
Senior Product Architect
Rocket Software
t: +1 781 684 2294 • m: +1 315 527 4764 • w: http://www.rocketsoftware.com/

From: Jerry Schulteis [mailto:mailto:[hidden email]]
Sent: Monday, August 14, 2017 5:21 PM
To: Alex Kodat <mailto:[hidden email]>
Cc: mailto:[hidden email]
Subject: Re: RE: Object.seal, read references, and code reliability

I'm ok with the basic idea. I don't think "lock" is a good name for it. Nothing about "Object.lock(myObj)" suggests that future access to a non-existent property of myObj will throw. Also "lock" carries a well-established, unrelated meaning in computer science.

Could this be done with an additional argument to Object.seal(), Object.freeze(), and Object.preventExtensions()?
Like so: "Object.seal(myObj, Object.THROW_ON_ABSENT_PROPERTY_READ)"--wordy, but the intent is unmistakable.
On Monday, August 14, 2017, 1:16:39 PM CDT, Alex Kodat <mailto:[hidden email]> wrote:


FWIW, I’m not sure I agree with your OrdinaryGet steps. Also, not sure I like readExtensible as it doesn’t really have anything to do with extensibility. Maybe readStrict? But maybe I’m thinking about extensibility wrong?

In any case, I think the description of [[Get]] would have to be like (sorry, I’ve never done this sort of spec pseudo code so some of this is probably syntactically incorrect):

[[Get]] (P, Receiver, ReadStrict)
1. Return ? OrdinaryGet(O, P, Receiver, ReadStrict).

And OrdinaryGet would be like:

OrdinaryGet (O, P, Receiver, ReadStrict)#
1. Assert: IsPropertyKey(P) is true.
2. Let desc be ? O.[[GetOwnProperty]](P).
3. If desc is undefined, then
a. Let readStrict be ? O.IsReadStrict(Receiver) || ReadStrict
b. Let parent be ? O.[[GetPrototypeOf]]().
c. If parent is null then
i.                     Assert: readStrict is false
ii.                    return undefined.
d. Return ? parent.[[Get]](P, Receiver, readStrict).
4. If IsDataDescriptor(desc) is true, return desc.[[Value]].
5. Assert: IsAccessorDescriptor(desc) is true.
6. Let getter be desc.[[Get]].
7. If getter is undefined, return undefined.
8. Return ? Call(getter, Receiver).

Probably adjustments need to be made to other references to [[Get]] and OrdinaryGet, passing false for ReadStrict.

I guess this pseudo code also points out an issue as to whether Object.lock would affect a dynamic property with no getter. Intuitively, it seems to me that it should.

------
Alex Kodat
Senior Product Architect
Rocket Software
t: +1 781 684 2294 • m: +1 315 527 4764 • w: http://www.rocketsoftware.com/

From: T.J. Crowder [mailto:[hidden email]]
Sent: Monday, August 14, 2017 12:00 PM
To: Alex Kodat <mailto:[hidden email]>
Cc: mailto:[hidden email]
Subject: Re: Object.seal, read references, and code reliability

On Mon, Aug 14, 2017 at 5:32 PM, Alex Kodat <mailto:[hidden email]> wrote:
> Is there any reason that there’s no flavor of Object.seal that
> would throw an exception on read references to properties that are
> not found on the specified object?

This sounds like a good idea at a high level. Will be very interested to know what implementers have to say about it from an implementation perspective.

In spec terms, at first glance it's mostly just a new pair of steps in [OrdinaryGet ordinary object internal function][1] (added Step 3.a and 3.b):

```text
1. Assert: IsPropertyKey(P) is true.
2. Let desc be ? O.[[GetOwnProperty]](P).
3. If desc is undefined, then
 a. Let readExtendable be ? IsReadExtensible(Receiver).
 b. If readExtendable is false, throw TypeError.
 c. Let parent be ? O.[[GetPrototypeOf]]().
 d. If parent is null, return undefined.
 e. Return ? parent.[[Get]](P, Receiver).
4. If IsDataDescriptor(desc) is true, return desc.[[Value]].
5. Assert: IsAccessorDescriptor(desc) is true.
6. Let getter be desc.[[Get]].
7. If getter is undefined, return undefined.
8. Return ? Call(getter, Receiver).
```

...where `IsReadExtensible` is an op to test the new flag. *(Used `pre` markdown to avoid the `[[...](.)` being treated as links without having to add `\` for those not reading the rendered version.)*

One concern is people already have trouble keeping sealed and frozen straight (or is that just me?). Adding a locked (or whatever) makes that even more confusing. But the semantics of sealed and frozen can't be changed to include this now.

-- T.J. Crowder

[1]: https://tc39.github.io/ecma262/#sec-ordinaryget
================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: +1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.
_______________________________________________
es-discuss mailing list
mailto:[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: +1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.

_______________________________________________
es-discuss mailing list
mailto:[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: +1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: RE: Object.seal, read references, and code reliability

Bob Myers
How could the compiler possibly know whether abc exists on foo?

Sorry for not being clearer.
It would know by means of appropriate type declarations/assertions.

Bob

On Tue, Aug 15, 2017 at 10:32 AM, Alex Kodat <[hidden email]> wrote:
It's not a compile-time check because a compile-time check is impossible:

   function noname(foo) {
      let abc = foo.abc;
    }

How could the compiler possibly know whether abc exists on foo?

------
Alex Kodat
Senior Product Architect
Rocket Software
t: +1 781 684 2294 • m: +1 315 527 4764 • w: http://www.rocketsoftware.com/

From: Bob Myers [mailto:[hidden email]]
Sent: Monday, August 14, 2017 11:55 PM
To: Alex Kodat <[hidden email]>
Cc: Jerry Schulteis <[hidden email]>; [hidden email]
Subject: Re: RE: Object.seal, read references, and code reliability

Is there some reason this is not just a compile-time type check?
Bob

On Tue, Aug 15, 2017 at 4:16 AM, Alex Kodat <mailto:[hidden email]> wrote:
Agree, lock’s not a good name. That was just a dumb name because I was too lazy to think of something better. Other names that come to mind (some also with other software connotations):

Object.box
Object.protect
Object.close
Object.guard
Object.fence
Object.shield

But don’t care that much and probably someone could come up with better. I guess of the above I like Object.guard. So I’ll use that for now…

Also, I’ll retract an earlier stupid statement I made where I suggested that if a property referenced an accessor descriptor without a getter it should throw if the guard bit is set. This is obviously wrong. As long as the property name is present, not having a getter is equivalent to the property being explicitly set to undefined which should not throw. That is:

let foo = Object.guard({a: 1, b: undefined});
console.log(foo.b);

should not throw.

Also, FWIW, I had originally thought of Object.guard as Object.seal on steroids but some thought makes me realize it’s really orthogonal and can picture cases where one might want to seal an object but not guard it and vice versa.

------
Alex Kodat
Senior Product Architect
Rocket Software
t: +1 781 684 2294 • m: +1 315 527 4764 • w: http://www.rocketsoftware.com/

From: Jerry Schulteis [mailto:[hidden email]:[hidden email]]
Sent: Monday, August 14, 2017 5:21 PM
To: Alex Kodat <mailto:[hidden email]>
Cc: mailto:[hidden email]
Subject: Re: RE: Object.seal, read references, and code reliability

I'm ok with the basic idea. I don't think "lock" is a good name for it. Nothing about "Object.lock(myObj)" suggests that future access to a non-existent property of myObj will throw. Also "lock" carries a well-established, unrelated meaning in computer science.

Could this be done with an additional argument to Object.seal(), Object.freeze(), and Object.preventExtensions()?
Like so: "Object.seal(myObj, Object.THROW_ON_ABSENT_PROPERTY_READ)"--wordy, but the intent is unmistakable.
On Monday, August 14, 2017, 1:16:39 PM CDT, Alex Kodat <mailto:[hidden email]> wrote:


FWIW, I’m not sure I agree with your OrdinaryGet steps. Also, not sure I like readExtensible as it doesn’t really have anything to do with extensibility. Maybe readStrict? But maybe I’m thinking about extensibility wrong?

In any case, I think the description of [[Get]] would have to be like (sorry, I’ve never done this sort of spec pseudo code so some of this is probably syntactically incorrect):

[[Get]] (P, Receiver, ReadStrict)
1. Return ? OrdinaryGet(O, P, Receiver, ReadStrict).

And OrdinaryGet would be like:

OrdinaryGet (O, P, Receiver, ReadStrict)#
1. Assert: IsPropertyKey(P) is true.
2. Let desc be ? O.[[GetOwnProperty]](P).
3. If desc is undefined, then
a. Let readStrict be ? O.IsReadStrict(Receiver) || ReadStrict
b. Let parent be ? O.[[GetPrototypeOf]]().
c. If parent is null then
i.                     Assert: readStrict is false
ii.                    return undefined.
d. Return ? parent.[[Get]](P, Receiver, readStrict).
4. If IsDataDescriptor(desc) is true, return desc.[[Value]].
5. Assert: IsAccessorDescriptor(desc) is true.
6. Let getter be desc.[[Get]].
7. If getter is undefined, return undefined.
8. Return ? Call(getter, Receiver).

Probably adjustments need to be made to other references to [[Get]] and OrdinaryGet, passing false for ReadStrict.

I guess this pseudo code also points out an issue as to whether Object.lock would affect a dynamic property with no getter. Intuitively, it seems to me that it should.

------
Alex Kodat
Senior Product Architect
Rocket Software
t: +1 781 684 2294 • m: +1 315 527 4764 • w: http://www.rocketsoftware.com/

From: T.J. Crowder [mailto:[hidden email]]
Sent: Monday, August 14, 2017 12:00 PM
To: Alex Kodat <mailto:[hidden email]>
Cc: mailto:[hidden email]
Subject: Re: Object.seal, read references, and code reliability

On Mon, Aug 14, 2017 at 5:32 PM, Alex Kodat <mailto:[hidden email]> wrote:
> Is there any reason that there’s no flavor of Object.seal that
> would throw an exception on read references to properties that are
> not found on the specified object?

This sounds like a good idea at a high level. Will be very interested to know what implementers have to say about it from an implementation perspective.

In spec terms, at first glance it's mostly just a new pair of steps in [OrdinaryGet ordinary object internal function][1] (added Step 3.a and 3.b):

```text
1. Assert: IsPropertyKey(P) is true.
2. Let desc be ? O.[[GetOwnProperty]](P).
3. If desc is undefined, then
 a. Let readExtendable be ? IsReadExtensible(Receiver).
 b. If readExtendable is false, throw TypeError.
 c. Let parent be ? O.[[GetPrototypeOf]]().
 d. If parent is null, return undefined.
 e. Return ? parent.[[Get]](P, Receiver).
4. If IsDataDescriptor(desc) is true, return desc.[[Value]].
5. Assert: IsAccessorDescriptor(desc) is true.
6. Let getter be desc.[[Get]].
7. If getter is undefined, return undefined.
8. Return ? Call(getter, Receiver).
```

...where `IsReadExtensible` is an op to test the new flag. *(Used `pre` markdown to avoid the `[[...](.)` being treated as links without having to add `\` for those not reading the rendered version.)*

One concern is people already have trouble keeping sealed and frozen straight (or is that just me?). Adding a locked (or whatever) makes that even more confusing. But the semantics of sealed and frozen can't be changed to include this now.

-- T.J. Crowder

[1]: https://tc39.github.io/ecma262/#sec-ordinaryget
================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: +1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.
_______________________________________________
es-discuss mailing list
mailto:[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: +1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.

_______________________________________________
es-discuss mailing list
mailto:[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: +1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: RE: Object.seal, read references, and code reliability

Jordan Harband
That's not a feature JavaScript has - you might be thinking of alternative languages, which are not JavaScript.

On Mon, Aug 14, 2017 at 10:21 PM, Bob Myers <[hidden email]> wrote:
How could the compiler possibly know whether abc exists on foo?

Sorry for not being clearer.
It would know by means of appropriate type declarations/assertions.

Bob

On Tue, Aug 15, 2017 at 10:32 AM, Alex Kodat <[hidden email]> wrote:
It's not a compile-time check because a compile-time check is impossible:

   function noname(foo) {
      let abc = foo.abc;
    }

How could the compiler possibly know whether abc exists on foo?

------
Alex Kodat
Senior Product Architect
Rocket Software
t: <a href="tel:(781)%20684-2294" value="+17816842294" target="_blank">+1 781 684 2294 • m: <a href="tel:(315)%20527-4764" value="+13155274764" target="_blank">+1 315 527 4764 • w: http://www.rocketsoftware.com/

From: Bob Myers [mailto:[hidden email]]
Sent: Monday, August 14, 2017 11:55 PM
To: Alex Kodat <[hidden email]>
Cc: Jerry Schulteis <[hidden email]>; [hidden email]
Subject: Re: RE: Object.seal, read references, and code reliability

Is there some reason this is not just a compile-time type check?
Bob

On Tue, Aug 15, 2017 at 4:16 AM, Alex Kodat <mailto:[hidden email]> wrote:
Agree, lock’s not a good name. That was just a dumb name because I was too lazy to think of something better. Other names that come to mind (some also with other software connotations):

Object.box
Object.protect
Object.close
Object.guard
Object.fence
Object.shield

But don’t care that much and probably someone could come up with better. I guess of the above I like Object.guard. So I’ll use that for now…

Also, I’ll retract an earlier stupid statement I made where I suggested that if a property referenced an accessor descriptor without a getter it should throw if the guard bit is set. This is obviously wrong. As long as the property name is present, not having a getter is equivalent to the property being explicitly set to undefined which should not throw. That is:

let foo = Object.guard({a: 1, b: undefined});
console.log(foo.b);

should not throw.

Also, FWIW, I had originally thought of Object.guard as Object.seal on steroids but some thought makes me realize it’s really orthogonal and can picture cases where one might want to seal an object but not guard it and vice versa.

------
Alex Kodat
Senior Product Architect
Rocket Software
t: <a href="tel:(781)%20684-2294" value="+17816842294" target="_blank">+1 781 684 2294 • m: <a href="tel:(315)%20527-4764" value="+13155274764" target="_blank">+1 315 527 4764 • w: http://www.rocketsoftware.com/

From: Jerry Schulteis [mailto:[hidden email]:[hidden email]]
Sent: Monday, August 14, 2017 5:21 PM
To: Alex Kodat <mailto:[hidden email]>
Cc: mailto:[hidden email]
Subject: Re: RE: Object.seal, read references, and code reliability

I'm ok with the basic idea. I don't think "lock" is a good name for it. Nothing about "Object.lock(myObj)" suggests that future access to a non-existent property of myObj will throw. Also "lock" carries a well-established, unrelated meaning in computer science.

Could this be done with an additional argument to Object.seal(), Object.freeze(), and Object.preventExtensions()?
Like so: "Object.seal(myObj, Object.THROW_ON_ABSENT_PROPERTY_READ)"--wordy, but the intent is unmistakable.
On Monday, August 14, 2017, 1:16:39 PM CDT, Alex Kodat <mailto:[hidden email]> wrote:


FWIW, I’m not sure I agree with your OrdinaryGet steps. Also, not sure I like readExtensible as it doesn’t really have anything to do with extensibility. Maybe readStrict? But maybe I’m thinking about extensibility wrong?

In any case, I think the description of [[Get]] would have to be like (sorry, I’ve never done this sort of spec pseudo code so some of this is probably syntactically incorrect):

[[Get]] (P, Receiver, ReadStrict)
1. Return ? OrdinaryGet(O, P, Receiver, ReadStrict).

And OrdinaryGet would be like:

OrdinaryGet (O, P, Receiver, ReadStrict)#
1. Assert: IsPropertyKey(P) is true.
2. Let desc be ? O.[[GetOwnProperty]](P).
3. If desc is undefined, then
a. Let readStrict be ? O.IsReadStrict(Receiver) || ReadStrict
b. Let parent be ? O.[[GetPrototypeOf]]().
c. If parent is null then
i.                     Assert: readStrict is false
ii.                    return undefined.
d. Return ? parent.[[Get]](P, Receiver, readStrict).
4. If IsDataDescriptor(desc) is true, return desc.[[Value]].
5. Assert: IsAccessorDescriptor(desc) is true.
6. Let getter be desc.[[Get]].
7. If getter is undefined, return undefined.
8. Return ? Call(getter, Receiver).

Probably adjustments need to be made to other references to [[Get]] and OrdinaryGet, passing false for ReadStrict.

I guess this pseudo code also points out an issue as to whether Object.lock would affect a dynamic property with no getter. Intuitively, it seems to me that it should.

------
Alex Kodat
Senior Product Architect
Rocket Software
t: <a href="tel:(781)%20684-2294" value="+17816842294" target="_blank">+1 781 684 2294 • m: <a href="tel:(315)%20527-4764" value="+13155274764" target="_blank">+1 315 527 4764 • w: http://www.rocketsoftware.com/

From: T.J. Crowder [mailto:[hidden email]]
Sent: Monday, August 14, 2017 12:00 PM
To: Alex Kodat <mailto:[hidden email]>
Cc: mailto:[hidden email]
Subject: Re: Object.seal, read references, and code reliability

On Mon, Aug 14, 2017 at 5:32 PM, Alex Kodat <mailto:[hidden email]> wrote:
> Is there any reason that there’s no flavor of Object.seal that
> would throw an exception on read references to properties that are
> not found on the specified object?

This sounds like a good idea at a high level. Will be very interested to know what implementers have to say about it from an implementation perspective.

In spec terms, at first glance it's mostly just a new pair of steps in [OrdinaryGet ordinary object internal function][1] (added Step 3.a and 3.b):

```text
1. Assert: IsPropertyKey(P) is true.
2. Let desc be ? O.[[GetOwnProperty]](P).
3. If desc is undefined, then
 a. Let readExtendable be ? IsReadExtensible(Receiver).
 b. If readExtendable is false, throw TypeError.
 c. Let parent be ? O.[[GetPrototypeOf]]().
 d. If parent is null, return undefined.
 e. Return ? parent.[[Get]](P, Receiver).
4. If IsDataDescriptor(desc) is true, return desc.[[Value]].
5. Assert: IsAccessorDescriptor(desc) is true.
6. Let getter be desc.[[Get]].
7. If getter is undefined, return undefined.
8. Return ? Call(getter, Receiver).
```

...where `IsReadExtensible` is an op to test the new flag. *(Used `pre` markdown to avoid the `[[...](.)` being treated as links without having to add `\` for those not reading the rendered version.)*

One concern is people already have trouble keeping sealed and frozen straight (or is that just me?). Adding a locked (or whatever) makes that even more confusing. But the semantics of sealed and frozen can't be changed to include this now.

-- T.J. Crowder

[1]: https://tc39.github.io/ecma262/#sec-ordinaryget
================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: <a href="tel:(877)%20328-2932" value="+18773282932" target="_blank">+1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.
_______________________________________________
es-discuss mailing list
mailto:[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: <a href="tel:(877)%20328-2932" value="+18773282932" target="_blank">+1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.

_______________________________________________
es-discuss mailing list
mailto:[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: <a href="tel:(877)%20328-2932" value="+18773282932" target="_blank">+1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: RE: Object.seal, read references, and code reliability

Bob Myers
> That's not a feature JavaScript has - you might be thinking of alternative languages, which are not JavaScript.

Yes, I know. JavaScript doesn't have `lock` either, yet here we are talking about it.

The OP is concerned about accesses to unknown or undefined properties. As I understand it, he proposes mechanisms to throw errors on attempts to make such accesses. 

The astronauts in the Mars lander would certainly not be happy with a solution involving the landing app crashing when it encountered some rare code path which accessed an unknown property on an object. I'm sure they'd prefer a compile-time error to be generated safely back on earth during the development process, long before the code shipped.

What I am saying is that as far as I can tell the OP's notion of locking is an attempt to add a feature to the language which amounts to enforcing type constraints at run-time. In my humble opinion, type constraints should be enforced during a type-checking phase, based on type assertions, annotations, declarations, inferences, and definitions. Yes, I know JS does not have those now. I hope it does sometime in the future. If it never does, then I don't think we should try to enforce them on a piece-meal basis via run-time checks and special locked statuses.

Bob

On Tue, Aug 15, 2017 at 10:55 AM, Jordan Harband <[hidden email]> wrote:
That's not a feature JavaScript has - you might be thinking of alternative languages, which are not JavaScript.

On Mon, Aug 14, 2017 at 10:21 PM, Bob Myers <[hidden email]> wrote:
How could the compiler possibly know whether abc exists on foo?

Sorry for not being clearer.
It would know by means of appropriate type declarations/assertions.

Bob

On Tue, Aug 15, 2017 at 10:32 AM, Alex Kodat <[hidden email]> wrote:
It's not a compile-time check because a compile-time check is impossible:

   function noname(foo) {
      let abc = foo.abc;
    }

How could the compiler possibly know whether abc exists on foo?

------
Alex Kodat
Senior Product Architect
Rocket Software
t: <a href="tel:(781)%20684-2294" value="+17816842294" target="_blank">+1 781 684 2294 • m: <a href="tel:(315)%20527-4764" value="+13155274764" target="_blank">+1 315 527 4764 • w: http://www.rocketsoftware.com/

From: Bob Myers [mailto:[hidden email]]
Sent: Monday, August 14, 2017 11:55 PM
To: Alex Kodat <[hidden email]>
Cc: Jerry Schulteis <[hidden email]>; [hidden email]
Subject: Re: RE: Object.seal, read references, and code reliability

Is there some reason this is not just a compile-time type check?
Bob

On Tue, Aug 15, 2017 at 4:16 AM, Alex Kodat <mailto:[hidden email]> wrote:
Agree, lock’s not a good name. That was just a dumb name because I was too lazy to think of something better. Other names that come to mind (some also with other software connotations):

Object.box
Object.protect
Object.close
Object.guard
Object.fence
Object.shield

But don’t care that much and probably someone could come up with better. I guess of the above I like Object.guard. So I’ll use that for now…

Also, I’ll retract an earlier stupid statement I made where I suggested that if a property referenced an accessor descriptor without a getter it should throw if the guard bit is set. This is obviously wrong. As long as the property name is present, not having a getter is equivalent to the property being explicitly set to undefined which should not throw. That is:

let foo = Object.guard({a: 1, b: undefined});
console.log(foo.b);

should not throw.

Also, FWIW, I had originally thought of Object.guard as Object.seal on steroids but some thought makes me realize it’s really orthogonal and can picture cases where one might want to seal an object but not guard it and vice versa.

------
Alex Kodat
Senior Product Architect
Rocket Software
t: <a href="tel:(781)%20684-2294" value="+17816842294" target="_blank">+1 781 684 2294 • m: <a href="tel:(315)%20527-4764" value="+13155274764" target="_blank">+1 315 527 4764 • w: http://www.rocketsoftware.com/

From: Jerry Schulteis [mailto:[hidden email]:[hidden email]]
Sent: Monday, August 14, 2017 5:21 PM
To: Alex Kodat <mailto:[hidden email]>
Cc: mailto:[hidden email]
Subject: Re: RE: Object.seal, read references, and code reliability

I'm ok with the basic idea. I don't think "lock" is a good name for it. Nothing about "Object.lock(myObj)" suggests that future access to a non-existent property of myObj will throw. Also "lock" carries a well-established, unrelated meaning in computer science.

Could this be done with an additional argument to Object.seal(), Object.freeze(), and Object.preventExtensions()?
Like so: "Object.seal(myObj, Object.THROW_ON_ABSENT_PROPERTY_READ)"--wordy, but the intent is unmistakable.
On Monday, August 14, 2017, 1:16:39 PM CDT, Alex Kodat <mailto:[hidden email]> wrote:


FWIW, I’m not sure I agree with your OrdinaryGet steps. Also, not sure I like readExtensible as it doesn’t really have anything to do with extensibility. Maybe readStrict? But maybe I’m thinking about extensibility wrong?

In any case, I think the description of [[Get]] would have to be like (sorry, I’ve never done this sort of spec pseudo code so some of this is probably syntactically incorrect):

[[Get]] (P, Receiver, ReadStrict)
1. Return ? OrdinaryGet(O, P, Receiver, ReadStrict).

And OrdinaryGet would be like:

OrdinaryGet (O, P, Receiver, ReadStrict)#
1. Assert: IsPropertyKey(P) is true.
2. Let desc be ? O.[[GetOwnProperty]](P).
3. If desc is undefined, then
a. Let readStrict be ? O.IsReadStrict(Receiver) || ReadStrict
b. Let parent be ? O.[[GetPrototypeOf]]().
c. If parent is null then
i.                     Assert: readStrict is false
ii.                    return undefined.
d. Return ? parent.[[Get]](P, Receiver, readStrict).
4. If IsDataDescriptor(desc) is true, return desc.[[Value]].
5. Assert: IsAccessorDescriptor(desc) is true.
6. Let getter be desc.[[Get]].
7. If getter is undefined, return undefined.
8. Return ? Call(getter, Receiver).

Probably adjustments need to be made to other references to [[Get]] and OrdinaryGet, passing false for ReadStrict.

I guess this pseudo code also points out an issue as to whether Object.lock would affect a dynamic property with no getter. Intuitively, it seems to me that it should.

------
Alex Kodat
Senior Product Architect
Rocket Software
t: <a href="tel:(781)%20684-2294" value="+17816842294" target="_blank">+1 781 684 2294 • m: <a href="tel:(315)%20527-4764" value="+13155274764" target="_blank">+1 315 527 4764 • w: http://www.rocketsoftware.com/

From: T.J. Crowder [mailto:[hidden email]]
Sent: Monday, August 14, 2017 12:00 PM
To: Alex Kodat <mailto:[hidden email]>
Cc: mailto:[hidden email]
Subject: Re: Object.seal, read references, and code reliability

On Mon, Aug 14, 2017 at 5:32 PM, Alex Kodat <mailto:[hidden email]> wrote:
> Is there any reason that there’s no flavor of Object.seal that
> would throw an exception on read references to properties that are
> not found on the specified object?

This sounds like a good idea at a high level. Will be very interested to know what implementers have to say about it from an implementation perspective.

In spec terms, at first glance it's mostly just a new pair of steps in [OrdinaryGet ordinary object internal function][1] (added Step 3.a and 3.b):

```text
1. Assert: IsPropertyKey(P) is true.
2. Let desc be ? O.[[GetOwnProperty]](P).
3. If desc is undefined, then
 a. Let readExtendable be ? IsReadExtensible(Receiver).
 b. If readExtendable is false, throw TypeError.
 c. Let parent be ? O.[[GetPrototypeOf]]().
 d. If parent is null, return undefined.
 e. Return ? parent.[[Get]](P, Receiver).
4. If IsDataDescriptor(desc) is true, return desc.[[Value]].
5. Assert: IsAccessorDescriptor(desc) is true.
6. Let getter be desc.[[Get]].
7. If getter is undefined, return undefined.
8. Return ? Call(getter, Receiver).
```

...where `IsReadExtensible` is an op to test the new flag. *(Used `pre` markdown to avoid the `[[...](.)` being treated as links without having to add `\` for those not reading the rendered version.)*

One concern is people already have trouble keeping sealed and frozen straight (or is that just me?). Adding a locked (or whatever) makes that even more confusing. But the semantics of sealed and frozen can't be changed to include this now.

-- T.J. Crowder

[1]: https://tc39.github.io/ecma262/#sec-ordinaryget
================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: <a href="tel:(877)%20328-2932" value="+18773282932" target="_blank">+1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.
_______________________________________________
es-discuss mailing list
mailto:[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: <a href="tel:(877)%20328-2932" value="+18773282932" target="_blank">+1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.

_______________________________________________
es-discuss mailing list
mailto:[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: <a href="tel:(877)%20328-2932" value="+18773282932" target="_blank">+1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

RE: Object.seal, read references, and code reliability

Alex Kodat
In reply to this post by Jordan Harband
Your points are goods ones. However, I believe .toString and .valueOf are on the Object prototype so should not be a problem. .then is on the Promise object prototype so also not a problem.

The well-known Symbols are indeed an issue. My inclination would be to exempt Symbols from Object.guard exceptions as their whole point is feature detection (wonder why toJSON didn't use a symbol?). The point of Object.guard is to catch extremely common screw-ups, AKA, typos or misunderstandings such as using foo.longlist when it should be foo.longList (or vice versa).

------
Alex Kodat
Senior Product Architect
Rocket Software
t: +1 781 684 2294 • m: +1 315 527 4764 • w: http://www.rocketsoftware.com/

From: Jordan Harband [mailto:[hidden email]]
Sent: Tuesday, August 15, 2017 12:02 AM
To: Alex Kodat <[hidden email]>
Cc: [hidden email]; [hidden email]
Subject: Re: Object.seal, read references, and code reliability

Don't forget besides `.toJSON`, all the other methods that builtins do a [[Get]] on: `.toString`, `.valueOf`, `.then`, and all the well-known symbols (Symbol.iterator, Symbol.isConcatSpreadable, etc) - and in node, `.inspect` in the repl.

You're totally right that Proxy, and ES5 getters before that, makes "accessing a property" always be something that can throw - just pointing out that there's a *lot* of places that `[[Get]]`s happen in the language.

On Mon, Aug 14, 2017 at 9:57 PM, Alex Kodat <mailto:[hidden email]> wrote:
On Mon Aug 14 18:49:35 UTC 2017 Don Griffin wrote
------------------------------------------------------------------------------------
<imho>Land mines like this are bad for JS. Reads should always be safe to do as in "foo && foo.bar". Throwing errors from that is always bad. duck-typing, feature detection etc are all valid uses for objects ... even sealed/frozen/locked/obfuscated ones :) </imho>

Just give me "undefined" on reads like these. I would much rather have that and possibly Object.isFrozen/isLocked/isSealed etc methods to test these conditions if appropriate.
------------------------------------------------------------------------------------
No one would force anyone to use Object.guard (what I initially called Object.lock). It would introduce no backward incompatibilities.

Whatever landmines this feature would introduce have been there at least since proxies were introduced since, with proxies, a get for a non-existent property might throw. In fact, even with a simple property getter you can get an exception from a getter. So the good old days when reads were always safe was a very long time ago. Of course, in your own code, you can very easily make your reads always safe and I'd say more power to you.

Duck-typing, feature detection, etc. can be wonderful things but so can objects with a well-defined set of properties. And in the latter case, it makes debugging much easier and faster if references to non-existent properties throw an exception.

Even in the face of Object.guard, feature detection could be done with Object.getOwnPropertyNames and Object.getPrototypeOf or Object.prototype.hasOwnProperty (the latter if one doesn't care about properties in prototype classes). In fact, as a general rule doing a feature test as if (foo.feature) is kinda sketchy as, of course, if foo.feature were 0 or "" or false your test would suggest a missing feature. Even if foo.feature returned undefined you don't know whether the property's explicitly set to undefined or simply not there (shame on you if there's a difference?).

Your e-mail does point to one minor fly in the ointment for the proposed Object.guard function, specifically the toJSON function for which a [[Get]] will be performed for every object being JSON.stringify'ed. This means that every object that is Object.guard'ed would require a toJSON in its prototype chain. A little annoying but a price to pay, I guess for using Object.guard. One would probably need to do the same for inspect. Of course one can set toJSON and inspect to undefined on the base Object prototype but that would probably be pretty uncool for most JavaScript engines.  There'd be other ways around this such as redefining JSON.stringify's use of toJSON to check for presence of the toJSON property before doing a [[Get]]. This would be indistinguishable from current behavior. And though it might seem expensive, I suspect most of the time there will be no toJSON property for most objects so the test for the property existence would be all that would be done.

------
Alex Kodat
Senior Product Architect
Rocket Software
t: tel:%2B1%20781%20684%202294 • m: tel:%2B1%20315%20527%204764 • w: http://www.rocketsoftware.com

================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: tel:%2B1%20877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.
_______________________________________________
es-discuss mailing list
mailto:[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: +1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Object.seal, read references, and code reliability

Jordan Harband
 - Every non-null/undefined value is checked for "then" when it's passed to a Promise's resolver, not just promises.

 - Every non-null/undefined value, including `Object.create(null)` or `new (class extends null {})`, has valueOf and/or toString checked when attempting to convert it to a primitive.

 - toJSON was added in 2009/2011; Symbols were added in 2015.

On Mon, Aug 14, 2017 at 10:41 PM, Alex Kodat <[hidden email]> wrote:
Your points are goods ones. However, I believe .toString and .valueOf are on the Object prototype so should not be a problem. .then is on the Promise object prototype so also not a problem.

The well-known Symbols are indeed an issue. My inclination would be to exempt Symbols from Object.guard exceptions as their whole point is feature detection (wonder why toJSON didn't use a symbol?). The point of Object.guard is to catch extremely common screw-ups, AKA, typos or misunderstandings such as using foo.longlist when it should be foo.longList (or vice versa).

------
Alex Kodat
Senior Product Architect
Rocket Software
t: <a href="tel:%2B1%20781%20684%202294" value="+17816842294">+1 781 684 2294 • m: <a href="tel:%2B1%20315%20527%204764" value="+13155274764">+1 315 527 4764 • w: http://www.rocketsoftware.com/

From: Jordan Harband [mailto:[hidden email]]
Sent: Tuesday, August 15, 2017 12:02 AM
To: Alex Kodat <[hidden email]>
Cc: [hidden email]; [hidden email]
Subject: Re: Object.seal, read references, and code reliability

Don't forget besides `.toJSON`, all the other methods that builtins do a [[Get]] on: `.toString`, `.valueOf`, `.then`, and all the well-known symbols (Symbol.iterator, Symbol.isConcatSpreadable, etc) - and in node, `.inspect` in the repl.

You're totally right that Proxy, and ES5 getters before that, makes "accessing a property" always be something that can throw - just pointing out that there's a *lot* of places that `[[Get]]`s happen in the language.

On Mon, Aug 14, 2017 at 9:57 PM, Alex Kodat <mailto:[hidden email]> wrote:
On Mon Aug 14 18:49:35 UTC 2017 Don Griffin wrote
------------------------------------------------------------------------------------
<imho>Land mines like this are bad for JS. Reads should always be safe to do as in "foo && foo.bar". Throwing errors from that is always bad. duck-typing, feature detection etc are all valid uses for objects ... even sealed/frozen/locked/obfuscated ones :) </imho>

Just give me "undefined" on reads like these. I would much rather have that and possibly Object.isFrozen/isLocked/isSealed etc methods to test these conditions if appropriate.
------------------------------------------------------------------------------------
No one would force anyone to use Object.guard (what I initially called Object.lock). It would introduce no backward incompatibilities.

Whatever landmines this feature would introduce have been there at least since proxies were introduced since, with proxies, a get for a non-existent property might throw. In fact, even with a simple property getter you can get an exception from a getter. So the good old days when reads were always safe was a very long time ago. Of course, in your own code, you can very easily make your reads always safe and I'd say more power to you.

Duck-typing, feature detection, etc. can be wonderful things but so can objects with a well-defined set of properties. And in the latter case, it makes debugging much easier and faster if references to non-existent properties throw an exception.

Even in the face of Object.guard, feature detection could be done with Object.getOwnPropertyNames and Object.getPrototypeOf or Object.prototype.hasOwnProperty (the latter if one doesn't care about properties in prototype classes). In fact, as a general rule doing a feature test as if (foo.feature) is kinda sketchy as, of course, if foo.feature were 0 or "" or false your test would suggest a missing feature. Even if foo.feature returned undefined you don't know whether the property's explicitly set to undefined or simply not there (shame on you if there's a difference?).

Your e-mail does point to one minor fly in the ointment for the proposed Object.guard function, specifically the toJSON function for which a [[Get]] will be performed for every object being JSON.stringify'ed. This means that every object that is Object.guard'ed would require a toJSON in its prototype chain. A little annoying but a price to pay, I guess for using Object.guard. One would probably need to do the same for inspect. Of course one can set toJSON and inspect to undefined on the base Object prototype but that would probably be pretty uncool for most JavaScript engines.  There'd be other ways around this such as redefining JSON.stringify's use of toJSON to check for presence of the toJSON property before doing a [[Get]]. This would be indistinguishable from current behavior. And though it might seem expensive, I suspect most of the time there will be no toJSON property for most objects so the test for the property existence would be all that would be done.

------
Alex Kodat
Senior Product Architect
Rocket Software
t: tel:%2B1%20781%20684%202294 • m: tel:%2B1%20315%20527%204764 • w: http://www.rocketsoftware.com

================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: tel:%2B1%20877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.
_______________________________________________
es-discuss mailing list
mailto:[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

================================
Rocket Software, Inc. and subsidiaries ■ 77 Fourth Avenue, Waltham MA 02451 ■ Main Office Toll Free Number: <a href="tel:%2B1%20877.328.2932" value="+18773282932">+1 877.328.2932
Contact Customer Support: https://my.rocketsoftware.com/RocketCommunity/RCEmailSupport
Unsubscribe from Marketing Messages/Manage Your Subscription Preferences - http://www.rocketsoftware.com/manage-your-email-preferences
Privacy Policy - http://www.rocketsoftware.com/company/legal/privacy-policy
================================

This communication and any attachments may contain confidential information of Rocket Software, Inc. All unauthorized use, disclosure or distribution is prohibited. If you are not the intended recipient, please notify Rocket Software immediately and destroy all copies of this communication. Thank you.


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Object.seal, read references, and code reliability

Isiah Meadows-2
In reply to this post by Alex Kodat
Just a quick note: Look up "strong mode", an experiment by Google attempting to look for code quality improvement and perf gains for locking class instances by default. I feel it's pretty relevant here, and here's a quick summary of their general findings:

1. It helped code quality only *a little* (stuff better code design could solve better)
2. It had very little gain in performance

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Object.seal, read references, and code reliability

T.J. Crowder-2
In reply to this post by Alex Kodat
On Mon, Aug 14, 2017 at 5:32 PM, Alex Kodat <[hidden email]> wrote:
> We’ve found Object.seal to be a huge aid in improving programmer
> productivity by catching coding errors early and preventing
> people from intentionally or unintentionally adding properties
> to objects outside the constructor.

Bob raised this but no one's actually said the name and you didn't mention it, so: If you haven't already, you might look into [TypeScript](http://typescriptlang.org), which does these things at compile time via type declarations (or with IDE support, even earlier). At least until/unless this idea goes somewhere. Your team seem to want the kind of constraints it puts on you.

-- T.J. Crowder


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
12