Small Proposal "!in"

classic Classic list List threaded Threaded
45 messages Options
123
Reply | Threaded
Open this post in threaded view
|

Small Proposal "!in"

Michael Theriot
I think `in` and `instanceof` could both benefit from having negated versions.

Assuming the developer is using `in` correctly, hasOwnProperty concerns are irrelevant. Either way they would attempt to use !(a in b), not !hasOwnProperty.

Same reason we don't use...
!(a == b) // a != b
!(a === b) // a !== b
!(a > b) // a <= b
(!(a > b) && !(a == b)) // a < b

On Thursday, June 28, 2018, Tobias Buschor <[hidden email]> wrote:
I dont like to write:
if ( !('x' in obj) &&  !('y' in obj) ) {
     doit()
}

I was even tempted to write it that way:
if ('x' in obj  ||  'y' in obj) { } else {
     doit()
}

What about a !in operator to write it like this?
if ('x' !in obj  &&  'y' !in obj) {
     doit()
}


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

Re: Small Proposal "!in"

Mike Samuel


On Wed, Jul 18, 2018 at 11:05 AM Michael Theriot <[hidden email]> wrote:
I think `in` and `instanceof` could both benefit from having negated versions.

Assuming the developer is using `in` correctly, hasOwnProperty concerns are irrelevant. Either way they would attempt to use !(a in b), not !hasOwnProperty.

Why should we assume the developer is using `in` correctly?
Apologies if I buried my question at the end.  It was, what are the use cases for `in` that would not be better served by an ergonomic, infix hasOwnProperty?


Same reason we don't use...
!(a == b) // a != b
!(a === b) // a !== b
 
!(a > b) // a <= b
(!(a > b) && !(a == b)) // a < b

I'm not sure this is relevant to your larger point, and I've already conceded ergonomics, but
these last two are not equivalent because NaN is weird.

a = NaN, b = 0
[!(a > b), a <= b]  // [true, false]
[!(a > b) && !(a == b), a < b]  // [true, false]



 
On Thursday, June 28, 2018, Tobias Buschor <[hidden email]> wrote:
I dont like to write:
if ( !('x' in obj) &&  !('y' in obj) ) {
     doit()
}

I was even tempted to write it that way:
if ('x' in obj  ||  'y' in obj) { } else {
     doit()
}

What about a !in operator to write it like this?
if ('x' !in obj  &&  'y' !in obj) {
     doit()
}

_______________________________________________
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
|

Fwd: Small Proposal "!in"

Mike Samuel
In reply to this post by Alexander Craggs
[sorry dropped group]

On Fri, Jul 13, 2018 at 11:36 AM <[hidden email]> wrote:
This may be a silly idea that doesn't come naturally to others, but the
first thing I thought of was "!n", where the "!" represents a flipped
"i", so the inverse of in.

You'd need yet another restricted production which would make infix `in` unrestricted
but the negation restricted.

x  // no semicolon inserted
in (obj)

x  // semicolon inserted
!n (obj)

Not a blocker, but worth keeping in mind.
I also have to look hard at them to distinguish.


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

Re: Small Proposal "!in"

Michael Theriot
In reply to this post by Mike Samuel
I think it is irrelevant; the operator already exists and I would assume if you want the negation of it you are using it correctly in the first place. Otherwise are you not just arguing for its removal altogether? But to answer your question one case that comes to mind is trapping get/has in a proxy handler.

On Wednesday, July 18, 2018, Mike Samuel <[hidden email]> wrote:


On Wed, Jul 18, 2018 at 11:05 AM Michael Theriot <[hidden email]> wrote:
I think `in` and `instanceof` could both benefit from having negated versions.

Assuming the developer is using `in` correctly, hasOwnProperty concerns are irrelevant. Either way they would attempt to use !(a in b), not !hasOwnProperty.

Why should we assume the developer is using `in` correctly?
Apologies if I buried my question at the end.  It was, what are the use cases for `in` that would not be better served by an ergonomic, infix hasOwnProperty?


Same reason we don't use...
!(a == b) // a != b
!(a === b) // a !== b
 
!(a > b) // a <= b
(!(a > b) && !(a == b)) // a < b

I'm not sure this is relevant to your larger point, and I've already conceded ergonomics, but
these last two are not equivalent because NaN is weird.

a = NaN, b = 0
[!(a > b), a <= b]  // [true, false]
[!(a > b) && !(a == b), a < b]  // [true, false]



 
On Thursday, June 28, 2018, Tobias Buschor <[hidden email]> wrote:
I dont like to write:
if ( !('x' in obj) &&  !('y' in obj) ) {
     doit()
}

I was even tempted to write it that way:
if ('x' in obj  ||  'y' in obj) { } else {
     doit()
}

What about a !in operator to write it like this?
if ('x' !in obj  &&  'y' !in obj) {
     doit()
}

_______________________________________________
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: Small Proposal "!in"

Mike Samuel


On Wed, Jul 18, 2018 at 12:21 PM Michael Theriot <[hidden email]> wrote:
I think it is irrelevant; the operator already exists and I would assume if you want the negation of it you are using it correctly in the first place. Otherwise are you not just arguing for its removal altogether? But to answer your question one case that comes to mind is trapping get/has in a proxy handler.

Why should we assume that only people who consistently use `in` correctly would want the negation?  It seems that people who use it incorrectly because they are confused about the precise semantics or don't care might want the negation too.  If there are more of the latter then we should not assume what you assume.

Proxy handler code is important, but very few developers will ever write a proxy handler over their careers, so this seems like a marginal use case.
Besides, Reflect.has is probably a better choice in a proxy handler.

I am not arguing for removing `in`.  That would break the web.  I am just arguing for prioritizing changes that provide features that more closely match the semantics developers typically want over making it more convenient to write code that seems to work in casual testing but has subtly wrong semantics.





 
On Wednesday, July 18, 2018, Mike Samuel <[hidden email]> wrote:


On Wed, Jul 18, 2018 at 11:05 AM Michael Theriot <[hidden email]> wrote:
I think `in` and `instanceof` could both benefit from having negated versions.

Assuming the developer is using `in` correctly, hasOwnProperty concerns are irrelevant. Either way they would attempt to use !(a in b), not !hasOwnProperty.

Why should we assume the developer is using `in` correctly?
Apologies if I buried my question at the end.  It was, what are the use cases for `in` that would not be better served by an ergonomic, infix hasOwnProperty?


Same reason we don't use...
!(a == b) // a != b
!(a === b) // a !== b
 
!(a > b) // a <= b
(!(a > b) && !(a == b)) // a < b

I'm not sure this is relevant to your larger point, and I've already conceded ergonomics, but
these last two are not equivalent because NaN is weird.

a = NaN, b = 0
[!(a > b), a <= b]  // [true, false]
[!(a > b) && !(a == b), a < b]  // [true, false]



 
On Thursday, June 28, 2018, Tobias Buschor <[hidden email]> wrote:
I dont like to write:
if ( !('x' in obj) &&  !('y' in obj) ) {
     doit()
}

I was even tempted to write it that way:
if ('x' in obj  ||  'y' in obj) { } else {
     doit()
}

What about a !in operator to write it like this?
if ('x' !in obj  &&  'y' !in obj) {
     doit()
}

_______________________________________________
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: Small Proposal "!in"

Tobias Buschor-2
There are valid use-cases.
As an example, some browsers have "onfocus" as an own property of "window", some as an inherited.

```js
if ('onfocus' !in window) {
    // polyfill onfocus...
}
```


Am Mi., 18. Juli 2018 um 18:32 Uhr schrieb Mike Samuel <[hidden email]>:


On Wed, Jul 18, 2018 at 12:21 PM Michael Theriot <[hidden email]> wrote:
I think it is irrelevant; the operator already exists and I would assume if you want the negation of it you are using it correctly in the first place. Otherwise are you not just arguing for its removal altogether? But to answer your question one case that comes to mind is trapping get/has in a proxy handler.

Why should we assume that only people who consistently use `in` correctly would want the negation?  It seems that people who use it incorrectly because they are confused about the precise semantics or don't care might want the negation too.  If there are more of the latter then we should not assume what you assume.

Proxy handler code is important, but very few developers will ever write a proxy handler over their careers, so this seems like a marginal use case.
Besides, Reflect.has is probably a better choice in a proxy handler.

I am not arguing for removing `in`.  That would break the web.  I am just arguing for prioritizing changes that provide features that more closely match the semantics developers typically want over making it more convenient to write code that seems to work in casual testing but has subtly wrong semantics.





 
On Wednesday, July 18, 2018, Mike Samuel <[hidden email]> wrote:


On Wed, Jul 18, 2018 at 11:05 AM Michael Theriot <[hidden email]> wrote:
I think `in` and `instanceof` could both benefit from having negated versions.

Assuming the developer is using `in` correctly, hasOwnProperty concerns are irrelevant. Either way they would attempt to use !(a in b), not !hasOwnProperty.

Why should we assume the developer is using `in` correctly?
Apologies if I buried my question at the end.  It was, what are the use cases for `in` that would not be better served by an ergonomic, infix hasOwnProperty?


Same reason we don't use...
!(a == b) // a != b
!(a === b) // a !== b
 
!(a > b) // a <= b
(!(a > b) && !(a == b)) // a < b

I'm not sure this is relevant to your larger point, and I've already conceded ergonomics, but
these last two are not equivalent because NaN is weird.

a = NaN, b = 0
[!(a > b), a <= b]  // [true, false]
[!(a > b) && !(a == b), a < b]  // [true, false]



 
On Thursday, June 28, 2018, Tobias Buschor <[hidden email]> wrote:
I dont like to write:
if ( !('x' in obj) &&  !('y' in obj) ) {
     doit()
}

I was even tempted to write it that way:
if ('x' in obj  ||  'y' in obj) { } else {
     doit()
}

What about a !in operator to write it like this?
if ('x' !in obj  &&  'y' !in obj) {
     doit()
}

_______________________________________________
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


--
Freundliche Grüsse
Tobias Buschor

schwups GmbH
Hauptstr. 33
9424 Rheineck/SG

+41 76 321 23 21

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

Re: Small Proposal "!in"

Andy Earnshaw-2
Although I support the idea of `!in` (for the same reasons as T.J. Crowder mentioned, plus it's useful for duck typing), what some browsers do isn't a great argument as modern browsers follow the spec more closely with regards to inherited accessors like this and you'd never be able to use `!in` for an older browser.  However, you do have a point in that accessors can live anywhere in the prototype chain and an object's properties may not necessarily be 'owned' by the object in question:

    document.createElement('input').hasOwnProperty('type')
    // false

So far, the main argument against has been that `hasOwnProperty()` is recommended over `in` as a more robust check.  I don't see how this is a valid concern, they clearly have different use cases and you're not going to solve that problem be excluding a negated `in` from the spec (`!(a in b)` is still easier to type than `!b.hasOwnProperty(a)`).  There are plenty of valid use cases for `in`, not least duck typing as mentioned before:

    function feed(duck) {
        if ('quackPitch' in duck && duck.canSwim) {
            duck.give(defrostedPeas);
        }
    }

`!in` and `!instanceof` would be great additions to the operator sets.

On Thu, 19 Jul 2018 at 12:06 Tobias Buschor <[hidden email]> wrote:
There are valid use-cases.
As an example, some browsers have "onfocus" as an own property of "window", some as an inherited.

```js
if ('onfocus' !in window) {
    // polyfill onfocus...
}
```


Am Mi., 18. Juli 2018 um 18:32 Uhr schrieb Mike Samuel <[hidden email]>:


On Wed, Jul 18, 2018 at 12:21 PM Michael Theriot <[hidden email]> wrote:
I think it is irrelevant; the operator already exists and I would assume if you want the negation of it you are using it correctly in the first place. Otherwise are you not just arguing for its removal altogether? But to answer your question one case that comes to mind is trapping get/has in a proxy handler.

Why should we assume that only people who consistently use `in` correctly would want the negation?  It seems that people who use it incorrectly because they are confused about the precise semantics or don't care might want the negation too.  If there are more of the latter then we should not assume what you assume.

Proxy handler code is important, but very few developers will ever write a proxy handler over their careers, so this seems like a marginal use case.
Besides, Reflect.has is probably a better choice in a proxy handler.

I am not arguing for removing `in`.  That would break the web.  I am just arguing for prioritizing changes that provide features that more closely match the semantics developers typically want over making it more convenient to write code that seems to work in casual testing but has subtly wrong semantics.





 
On Wednesday, July 18, 2018, Mike Samuel <[hidden email]> wrote:


On Wed, Jul 18, 2018 at 11:05 AM Michael Theriot <[hidden email]> wrote:
I think `in` and `instanceof` could both benefit from having negated versions.

Assuming the developer is using `in` correctly, hasOwnProperty concerns are irrelevant. Either way they would attempt to use !(a in b), not !hasOwnProperty.

Why should we assume the developer is using `in` correctly?
Apologies if I buried my question at the end.  It was, what are the use cases for `in` that would not be better served by an ergonomic, infix hasOwnProperty?


Same reason we don't use...
!(a == b) // a != b
!(a === b) // a !== b
 
!(a > b) // a <= b
(!(a > b) && !(a == b)) // a < b

I'm not sure this is relevant to your larger point, and I've already conceded ergonomics, but
these last two are not equivalent because NaN is weird.

a = NaN, b = 0
[!(a > b), a <= b]  // [true, false]
[!(a > b) && !(a == b), a < b]  // [true, false]



 
On Thursday, June 28, 2018, Tobias Buschor <[hidden email]> wrote:
I dont like to write:
if ( !('x' in obj) &&  !('y' in obj) ) {
     doit()
}

I was even tempted to write it that way:
if ('x' in obj  ||  'y' in obj) { } else {
     doit()
}

What about a !in operator to write it like this?
if ('x' !in obj  &&  'y' !in obj) {
     doit()
}

_______________________________________________
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


--
Freundliche Grüsse
Tobias Buschor

schwups GmbH
Hauptstr. 33
9424 Rheineck/SG

<a href="tel:+41%2076%20321%2023%2021" value="+41763212321" target="_blank">+41 76 321 23 21
_______________________________________________
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: Small Proposal "!in"

Mike Samuel


On Thu, Jul 19, 2018 at 7:32 AM Andy Earnshaw <[hidden email]> wrote:
Although I support the idea of `!in` (for the same reasons as T.J. Crowder mentioned, plus it's useful for duck typing), what some browsers do isn't a great argument as modern browsers follow the spec more closely with regards to inherited accessors like this and you'd never be able to use `!in` for an older browser.  However, you do have a point in that accessors can live anywhere in the prototype chain and an object's properties may not necessarily be 'owned' by the object in question:

    document.createElement('input').hasOwnProperty('type')
    // false

'string' === typeof document.createElement('input').type
// true
 
So far, the main argument against has been that `hasOwnProperty()` is recommended over `in` as a more robust check.  I don't see how this is a valid concern, they clearly have different use cases and you're not going to solve that problem be excluding a negated `in` from the spec (`!(a in b)` is still easier to type than `!b.hasOwnProperty(a)`).  There are plenty of valid use cases for `in`, not least duck typing as mentioned before:

Agree re "not solving that problem by"
When I'm duck typing, I typically am testing typeof or truthiness of a property, not just presence.

    function feed(duck) {
        if ('quackPitch' in duck && duck.canSwim) {
            duck.give(defrostedPeas);
        }
    }

This code is brittle.  An attacker may be able to deny service by getting `{ "quackPitch": true, "canSwim": true }` to a JSON decoder, but would not be able to trigger an exception if you tested with typeof instead of in.

function robustFeed(duck) {
  if (duck.canSwim && typeof duck.give === 'function') {
    duck.give(defrostedPeas);
  }
}

`in` provides a weak, confusable kind of duck typing.
JSON decoding attacks allow forging objects that satisfy `in` predicates, encouraging conflating
objects from an untrusted source with objects from trusted code.
These forgeries often would not pass stronger predicates that test for the typeof required properties.
 
`!in` and `!instanceof` would be great additions to the operator sets.

Agree re !instanceof.  I'm still not seeing where developers do and should use `in` or `!in` on a regular basis.
 
On Thu, 19 Jul 2018 at 12:06 Tobias Buschor <[hidden email]> wrote:
There are valid use-cases.
As an example, some browsers have "onfocus" as an own property of "window", some as an inherited.

```js
if ('onfocus' !in window) {
    // polyfill onfocus...
}
```


Am Mi., 18. Juli 2018 um 18:32 Uhr schrieb Mike Samuel <[hidden email]>:


On Wed, Jul 18, 2018 at 12:21 PM Michael Theriot <[hidden email]> wrote:
I think it is irrelevant; the operator already exists and I would assume if you want the negation of it you are using it correctly in the first place. Otherwise are you not just arguing for its removal altogether? But to answer your question one case that comes to mind is trapping get/has in a proxy handler.

Why should we assume that only people who consistently use `in` correctly would want the negation?  It seems that people who use it incorrectly because they are confused about the precise semantics or don't care might want the negation too.  If there are more of the latter then we should not assume what you assume.

Proxy handler code is important, but very few developers will ever write a proxy handler over their careers, so this seems like a marginal use case.
Besides, Reflect.has is probably a better choice in a proxy handler.

I am not arguing for removing `in`.  That would break the web.  I am just arguing for prioritizing changes that provide features that more closely match the semantics developers typically want over making it more convenient to write code that seems to work in casual testing but has subtly wrong semantics.





 
On Wednesday, July 18, 2018, Mike Samuel <[hidden email]> wrote:


On Wed, Jul 18, 2018 at 11:05 AM Michael Theriot <[hidden email]> wrote:
I think `in` and `instanceof` could both benefit from having negated versions.

Assuming the developer is using `in` correctly, hasOwnProperty concerns are irrelevant. Either way they would attempt to use !(a in b), not !hasOwnProperty.

Why should we assume the developer is using `in` correctly?
Apologies if I buried my question at the end.  It was, what are the use cases for `in` that would not be better served by an ergonomic, infix hasOwnProperty?


Same reason we don't use...
!(a == b) // a != b
!(a === b) // a !== b
 
!(a > b) // a <= b
(!(a > b) && !(a == b)) // a < b

I'm not sure this is relevant to your larger point, and I've already conceded ergonomics, but
these last two are not equivalent because NaN is weird.

a = NaN, b = 0
[!(a > b), a <= b]  // [true, false]
[!(a > b) && !(a == b), a < b]  // [true, false]



 
On Thursday, June 28, 2018, Tobias Buschor <[hidden email]> wrote:
I dont like to write:
if ( !('x' in obj) &&  !('y' in obj) ) {
     doit()
}

I was even tempted to write it that way:
if ('x' in obj  ||  'y' in obj) { } else {
     doit()
}

What about a !in operator to write it like this?
if ('x' !in obj  &&  'y' !in obj) {
     doit()
}

_______________________________________________
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


--
Freundliche Grüsse
Tobias Buschor

schwups GmbH
Hauptstr. 33
9424 Rheineck/SG

<a href="tel:+41%2076%20321%2023%2021" value="+41763212321" target="_blank">+41 76 321 23 21
_______________________________________________
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: Small Proposal "!in"

Michael Theriot
> 'string' === typeof document.createElement('input').type
> // true

It should be noted this is a "loose check"; it does not determine whether or not the property exists when its value equals undefined. It also triggers getters, whereas `in` reports whether or not the property exists without triggering a getter.

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

Re: Small Proposal "!in"

T.J. Crowder-2
In reply to this post by Andy Earnshaw-2
On Thu, Jul 19, 2018 at 12:32 PM, Andy Earnshaw
<[hidden email]> wrote:
> Although I support the idea of `!in` (for the same reasons as T.J. Crowder
> mentioned, plus it's useful for duck typing), what some browsers do isn't a
> great argument as modern browsers follow the spec more closely with regards
> to inherited accessors like this and you'd never be able to use `!in` for an
> older browser.

Well, there's transpiling.

> `!in` and `!instanceof` would be great additions to the operator sets.

AND, agreeing with Mike Samuel, an ergonomic operator for `hasOwnProperty` (that doesn't have the issues of being overridden, not being inherited because `Object.prototype` isn't in the object's prototype chain, etc.) would be a great addition. I don't see any reason they couldn't all be part of the same proposal as they touch the same parts of the spec and implementations. And agree that the own property ones would be the more useful ones, but there are use cases for both.

The immediate temptation is `hasOwn` and `!hasOwn`. My only concern is that their operands would be in the opposite order to `in` and `!in`:

```js
const o = Object.create({a: 1});
o.b = 2;
console.log("a" in o);     // true
console.log(o hasOwn "a"); // false
console.log("b" in o);     // true
console.log(o hasOwn "b"); // true
```

For me, `hasOwn` with the different operand order isn't a problem, but others may take a different view. Trying to keep the same order takes us down a route like `inOwn` which I can't say I care for.

But I wonder if all of this discussion is useful. If someone *did* take the time to work out the naming and do a proper draft proposal, perhaps a Babel plugin, is there really any likelihood of someone championing it? I'd see these contents:

* `name !in obj`, `name notin obj`, or whatever it gets called
* `obj hasOwn name`, `name inOwn obj`, or whatever it gets called
* `obj !hasOwn name`, `name !inOwn obj`, or whatever it gets called
* `Reflect.hasOwn`, the "own" version of `Reflect.has`
* `Proxy` trap for `hasOwn` (even if the operator has a different name)

Is there anyone appropriately-placed who can say "Yeah, if someone spends the time to investigate this and put together a really proper proposal, I'm willing to look at that proposal with an eye toward _possibly_ championing it." I mean, if there's a 10% chance or better, it may be worth someone's time. If there isn't, then...

-- 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: Small Proposal "!in"

Mike Samuel
In reply to this post by Michael Theriot


On Thu, Jul 19, 2018 at 9:26 AM Michael Theriot <[hidden email]> wrote:
> 'string' === typeof document.createElement('input').type
> // true

It should be noted this is a "loose check"; it does not determine whether or not the property exists when its value equals undefined. It also triggers getters, whereas `in` reports whether or not the property exists without triggering a getter.

Good point.   `in` does trigger "has" proxy handlers though, so neither is side-effect free.

 
_______________________________________________
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: Small Proposal "!in"

T.J. Crowder-2
In reply to this post by T.J. Crowder-2
On Thu, Jul 19, 2018 at 2:44 PM, T.J. Crowder <[hidden email]> wrote:
> Is there anyone appropriately-placed who can say "Yeah, if someone spends
> the time to investigate this and put together a really proper proposal, I'm
> willing to look at that proposal with an eye toward _possibly_ championing
> it."

Apologies, Mike, I just realized you're a potential champion. Just in case you read that as seeming a bit off... :-)

-- 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: Small Proposal "!in"

Andy Earnshaw-2
In reply to this post by Mike Samuel
It was a contrived example I threw together to make a point in 30 seconds.  It may surprise you to know that it is not real world code.  You talk about an "attacker" as if any code working in such a way is sensitive, but that is often not the case and leaving your functions intentionally generic allows third parties more room when working with it.

> 'string' === typeof document.createElement('input').type
> // true

Again, you're missing the point, which is how that is one example of an object that doesn't 'own' all of its properties.  As already mentioned, it also triggers a getter.

Let's not also forget that not all code has to adhere to best practices.  I use the `in` operator far more in the REPL/console or when I'm prototyping than I do when I'm performing robust checks in code.

On Thu, 19 Jul 2018 at 13:23 Mike Samuel <[hidden email]> wrote:
On Thu, Jul 19, 2018 at 7:32 AM Andy Earnshaw <[hidden email]> wrote:
Although I support the idea of `!in` (for the same reasons as T.J. Crowder mentioned, plus it's useful for duck typing), what some browsers do isn't a great argument as modern browsers follow the spec more closely with regards to inherited accessors like this and you'd never be able to use `!in` for an older browser.  However, you do have a point in that accessors can live anywhere in the prototype chain and an object's properties may not necessarily be 'owned' by the object in question:

    document.createElement('input').hasOwnProperty('type')
    // false

'string' === typeof document.createElement('input').type
// true
 
So far, the main argument against has been that `hasOwnProperty()` is recommended over `in` as a more robust check.  I don't see how this is a valid concern, they clearly have different use cases and you're not going to solve that problem be excluding a negated `in` from the spec (`!(a in b)` is still easier to type than `!b.hasOwnProperty(a)`).  There are plenty of valid use cases for `in`, not least duck typing as mentioned before:

Agree re "not solving that problem by"
When I'm duck typing, I typically am testing typeof or truthiness of a property, not just presence.

    function feed(duck) {
        if ('quackPitch' in duck && duck.canSwim) {
            duck.give(defrostedPeas);
        }
    }

This code is brittle.  An attacker may be able to deny service by getting `{ "quackPitch": true, "canSwim": true }` to a JSON decoder, but would not be able to trigger an exception if you tested with typeof instead of in.

function robustFeed(duck) {
  if (duck.canSwim && typeof duck.give === 'function') {
    duck.give(defrostedPeas);
  }
}

`in` provides a weak, confusable kind of duck typing.
JSON decoding attacks allow forging objects that satisfy `in` predicates, encouraging conflating
objects from an untrusted source with objects from trusted code.
These forgeries often would not pass stronger predicates that test for the typeof required properties.
 
`!in` and `!instanceof` would be great additions to the operator sets.

Agree re !instanceof.  I'm still not seeing where developers do and should use `in` or `!in` on a regular basis.
 
On Thu, 19 Jul 2018 at 12:06 Tobias Buschor <[hidden email]> wrote:
There are valid use-cases.
As an example, some browsers have "onfocus" as an own property of "window", some as an inherited.

```js
if ('onfocus' !in window) {
    // polyfill onfocus...
}
```


Am Mi., 18. Juli 2018 um 18:32 Uhr schrieb Mike Samuel <[hidden email]>:


On Wed, Jul 18, 2018 at 12:21 PM Michael Theriot <[hidden email]> wrote:
I think it is irrelevant; the operator already exists and I would assume if you want the negation of it you are using it correctly in the first place. Otherwise are you not just arguing for its removal altogether? But to answer your question one case that comes to mind is trapping get/has in a proxy handler.

Why should we assume that only people who consistently use `in` correctly would want the negation?  It seems that people who use it incorrectly because they are confused about the precise semantics or don't care might want the negation too.  If there are more of the latter then we should not assume what you assume.

Proxy handler code is important, but very few developers will ever write a proxy handler over their careers, so this seems like a marginal use case.
Besides, Reflect.has is probably a better choice in a proxy handler.

I am not arguing for removing `in`.  That would break the web.  I am just arguing for prioritizing changes that provide features that more closely match the semantics developers typically want over making it more convenient to write code that seems to work in casual testing but has subtly wrong semantics.





 
On Wednesday, July 18, 2018, Mike Samuel <[hidden email]> wrote:


On Wed, Jul 18, 2018 at 11:05 AM Michael Theriot <[hidden email]> wrote:
I think `in` and `instanceof` could both benefit from having negated versions.

Assuming the developer is using `in` correctly, hasOwnProperty concerns are irrelevant. Either way they would attempt to use !(a in b), not !hasOwnProperty.

Why should we assume the developer is using `in` correctly?
Apologies if I buried my question at the end.  It was, what are the use cases for `in` that would not be better served by an ergonomic, infix hasOwnProperty?


Same reason we don't use...
!(a == b) // a != b
!(a === b) // a !== b
 
!(a > b) // a <= b
(!(a > b) && !(a == b)) // a < b

I'm not sure this is relevant to your larger point, and I've already conceded ergonomics, but
these last two are not equivalent because NaN is weird.

a = NaN, b = 0
[!(a > b), a <= b]  // [true, false]
[!(a > b) && !(a == b), a < b]  // [true, false]



 
On Thursday, June 28, 2018, Tobias Buschor <[hidden email]> wrote:
I dont like to write:
if ( !('x' in obj) &&  !('y' in obj) ) {
     doit()
}

I was even tempted to write it that way:
if ('x' in obj  ||  'y' in obj) { } else {
     doit()
}

What about a !in operator to write it like this?
if ('x' !in obj  &&  'y' !in obj) {
     doit()
}

_______________________________________________
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


--
Freundliche Grüsse
Tobias Buschor

schwups GmbH
Hauptstr. 33
9424 Rheineck/SG

<a href="tel:+41%2076%20321%2023%2021" value="+41763212321" target="_blank">+41 76 321 23 21
_______________________________________________
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: Small Proposal "!in"

Naveen Chawla
In reply to this post by T.J. Crowder-2
I still prefer truthy checks when logically valid. Otherwise a truthy check + [any other validity check in the logic]. I find `in` far too quirky and I'd rather never ever use it.

I think `instanceof` is also a messy pattern. I've always preferred having an overridden method on the object that performs the necessary logic for that type, instead of if(x instanceof Y)... I find overridden method based code shorter at the point of use, and scales to many instances / permutations for type based logic.

Therefore, I'd rather TC39 let these concepts like `in` and `instanceof` die quietly, and always focus on the more/most powerful ways of getting things done first.

On Thu, 19 Jul 2018 at 19:14 T.J. Crowder <[hidden email]> wrote:
On Thu, Jul 19, 2018 at 12:32 PM, Andy Earnshaw
<[hidden email]> wrote:
> Although I support the idea of `!in` (for the same reasons as T.J. Crowder
> mentioned, plus it's useful for duck typing), what some browsers do isn't a
> great argument as modern browsers follow the spec more closely with regards
> to inherited accessors like this and you'd never be able to use `!in` for an
> older browser.

Well, there's transpiling.


> `!in` and `!instanceof` would be great additions to the operator sets.

AND, agreeing with Mike Samuel, an ergonomic operator for `hasOwnProperty` (that doesn't have the issues of being overridden, not being inherited because `Object.prototype` isn't in the object's prototype chain, etc.) would be a great addition. I don't see any reason they couldn't all be part of the same proposal as they touch the same parts of the spec and implementations. And agree that the own property ones would be the more useful ones, but there are use cases for both.

The immediate temptation is `hasOwn` and `!hasOwn`. My only concern is that their operands would be in the opposite order to `in` and `!in`:

```js
const o = Object.create({a: 1});
o.b = 2;
console.log("a" in o);     // true
console.log(o hasOwn "a"); // false
console.log("b" in o);     // true
console.log(o hasOwn "b"); // true
```

For me, `hasOwn` with the different operand order isn't a problem, but others may take a different view. Trying to keep the same order takes us down a route like `inOwn` which I can't say I care for.

But I wonder if all of this discussion is useful. If someone *did* take the time to work out the naming and do a proper draft proposal, perhaps a Babel plugin, is there really any likelihood of someone championing it? I'd see these contents:

* `name !in obj`, `name notin obj`, or whatever it gets called
* `obj hasOwn name`, `name inOwn obj`, or whatever it gets called
* `obj !hasOwn name`, `name !inOwn obj`, or whatever it gets called
* `Reflect.hasOwn`, the "own" version of `Reflect.has`
* `Proxy` trap for `hasOwn` (even if the operator has a different name)

Is there anyone appropriately-placed who can say "Yeah, if someone spends the time to investigate this and put together a really proper proposal, I'm willing to look at that proposal with an eye toward _possibly_ championing it." I mean, if there's a 10% chance or better, it may be worth someone's time. If there isn't, then...

-- T.J. Crowder
_______________________________________________
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: Small Proposal "!in"

Andy Earnshaw-2
In reply to this post by T.J. Crowder-2
On Thu, 19 Jul 2018 at 14:44 T.J. Crowder <[hidden email]> wrote:
On Thu, Jul 19, 2018 at 12:32 PM, Andy Earnshaw
<[hidden email]> wrote:
> Although I support the idea of `!in` (for the same reasons as T.J. Crowder
> mentioned, plus it's useful for duck typing), what some browsers do isn't a
> great argument as modern browsers follow the spec more closely with regards
> to inherited accessors like this and you'd never be able to use `!in` for an
> older browser.

Well, there's transpiling.

Good point.
 
> `!in` and `!instanceof` would be great additions to the operator sets.

AND, agreeing with Mike Samuel, an ergonomic operator for `hasOwnProperty` (that doesn't have the issues of being overridden, not being inherited because `Object.prototype` isn't in the object's prototype chain, etc.) would be a great addition. I don't see any reason they couldn't all be part of the same proposal as they touch the same parts of the spec and implementations. And agree that the own property ones would be the more useful ones, but there are use cases for both.

The immediate temptation is `hasOwn` and `!hasOwn`. My only concern is that their operands would be in the opposite order to `in` and `!in`:

I'm not against this at all.  I just think the arguments against `!in` aren't really arguments against it.  Adding `!hasOwn` would give even more weight to an `!in` proposal, I think.
 
For me, `hasOwn` with the different operand order isn't a problem, but others may take a different view. Trying to keep the same order takes us down a route like `inOwn` which I can't say I care for.

Nor me. I would argue for `on` (`'a' on b`), but that is a huge typo footgun (especially for Colemak users) and maybe isn't clear enough about its semantics.  I would argue that operators aren't camel cased in JS though, so `hasown`/`inown`.
 

But I wonder if all of this discussion is useful. If someone *did* take the time to work out the naming and do a proper draft proposal, perhaps a Babel plugin, is there really any likelihood of someone championing it? I'd see these contents:

* `name !in obj`, `name notin obj`, or whatever it gets called
* `obj hasOwn name`, `name inOwn obj`, or whatever it gets called
* `obj !hasOwn name`, `name !inOwn obj`, or whatever it gets called
* `Reflect.hasOwn`, the "own" version of `Reflect.has`
* `Proxy` trap for `hasOwn` (even if the operator has a different name)

Is there anyone appropriately-placed who can say "Yeah, if someone spends the time to investigate this and put together a really proper proposal, I'm willing to look at that proposal with an eye toward _possibly_ championing it." I mean, if there's a 10% chance or better, it may be worth someone's time. If there isn't, then...

`!in` and `!instanceof` are low hanging fruit (run the same steps as their counterparts but flip the result), better off in their own proposal. I don't know if you'd find a champion to do it, but I do think a lot of people would find them convenient.

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

Re: Small Proposal "!in"

Andy Earnshaw-2
In reply to this post by Mike Samuel


On Thu, 19 Jul 2018 at 14:48 Mike Samuel <[hidden email]> wrote:
On Thu, Jul 19, 2018 at 9:26 AM Michael Theriot <[hidden email]> wrote:
> 'string' === typeof document.createElement('input').type
> // true

It should be noted this is a "loose check"; it does not determine whether or not the property exists when its value equals undefined. It also triggers getters, whereas `in` reports whether or not the property exists without triggering a getter.

Good point.   `in` does trigger "has" proxy handlers though, so neither is side-effect free.

Except I'd argue this is a desirable side effect in the case of `in` and less so in the case of a getter.  Getters are more likely to be an intensive operation (for example, innerHTML) than a proxy `has` operation generally overriding the expected behaviour of the target object.

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

Re: Small Proposal "!in"

Augusto Moura
In reply to this post by Michael Theriot
In most of the use cases of checking if a property is in the prototype chain (checking a protocol for example) you *do* want to trigger getters and Proxy traps. When interfacing with a object a developer doesn't need to be concerned with the implementation behind, if a getter or proxy trap does a intensive computation or has side effects, it's all bad class/object design fault. A common example when you want to check a property "return" rather than it's existence it's virtual properties or class refactoring:
``` js
// old implementation
class Foo {
  constructor() {
    this.foo = 46;
  }
}

// post refactoring
class Foo {
  // implements something different

  // Product of refactoring, undefined it's a placeholder here
  //it can be any value that makes sense in the refactoring
  get foo() { return undefined; }
  set foo(_) {}
}
```
Of course there's some use cases to use property check without triggering side effects (mostly when working with property descriptors), but the majority of "property existence check" lays on interface assertion and a typeof check it's ~generally~ the right choice.

About the `!in` operator, I don't see any problem in it. Of couse the usage of `in` is most of the time is not recommended, but it has it place. Also it puts precedence to future operators (like the `hasOwn` proposed here).

Em qui, 19 de jul de 2018 às 10:26, Michael Theriot <[hidden email]> escreveu:
> 'string' === typeof document.createElement('input').type
> // true

It should be noted this is a "loose check"; it does not determine whether or not the property exists when its value equals undefined. It also triggers getters, whereas `in` reports whether or not the property exists without triggering a getter.
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
--
Augusto Moura

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

Re: Small Proposal "!in"

Mike Samuel


On Thu, Jul 19, 2018 at 10:40 AM Augusto Moura <[hidden email]> wrote:
Of couse the usage of `in` is most of the time is not recommended, but it has it place. 

What places does it have?
I remain unconvinced that `in` has significant enough use cases to warrant high-level ergonomics
were it being proposed today.

It exists, and it'll probably never be removed from the language, but I don't think it should be taught
as a good part of the language, and linters should probably flag it.


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

Re: Small Proposal "!in"

Michael Theriot
For me, `hasOwn` with the different operand order isn't a problem, but others may take a different view. Trying to keep the same order takes us down a route like `inOwn` which I can't say I care for.

Nor me. I would argue for `on` (`'a' on b`), but that is a huge typo footgun (especially for Colemak users) and maybe isn't clear enough about its semantics.  I would argue that operators aren't camel cased in JS though, so `hasown`/`inown`.

For what it's worth I was also thinking of an "on" operator when reading this message, so this is intuitive to me. I also think that is a separate idea to propose though.

Of couse the usage of `in` is most of the time is not recommended, but it has it place. 

What places does it have?
I remain unconvinced that `in` has significant enough use cases to warrant high-level ergonomics
were it being proposed today.

It exists, and it'll probably never be removed from the language, but I don't think it should be taught
as a good part of the language, and linters should probably flag it.

Maybe a radical thought, but does this not apply to hasOwnProperty? If you have strong type management why test for a property? The one case I can think of is parsing JSON but I handle that with destructuring. Are there significant use cases for it? Should linters flag it?

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

Re: Small Proposal "!in"

Mike Samuel


On Thu, Jul 19, 2018 at 11:56 AM Michael Theriot <[hidden email]> wrote:
For me, `hasOwn` with the different operand order isn't a problem, but others may take a different view. Trying to keep the same order takes us down a route like `inOwn` which I can't say I care for.

Nor me. I would argue for `on` (`'a' on b`), but that is a huge typo footgun (especially for Colemak users) and maybe isn't clear enough about its semantics.  I would argue that operators aren't camel cased in JS though, so `hasown`/`inown`.

For what it's worth I was also thinking of an "on" operator when reading this message, so this is intuitive to me. I also think that is a separate idea to propose though.

"on" is a good name.  Agree on separate.

 
Of couse the usage of `in` is most of the time is not recommended, but it has it place. 

What places does it have?
I remain unconvinced that `in` has significant enough use cases to warrant high-level ergonomics
were it being proposed today.

It exists, and it'll probably never be removed from the language, but I don't think it should be taught
as a good part of the language, and linters should probably flag it.

Maybe a radical thought, but does this not apply to hasOwnProperty? If you have strong type management why test for a property? The one case I can think of is parsing JSON but I handle that with destructuring. Are there significant use cases for it? Should linters flag it?

Good questions.
Linters should flag
   x.hasOwnProperty(y)
since if you're unsure whether x has an own property y you're probably unsure whether x has an own property 'hasOwnProperty'.

IIRC, destructuring traverses prototypes so see caveat about library code and monkeypatching below.
const { toString: f } = {}
typeof f // 'funciton'

You're right that in the middle of an application an instance's type should determine whether a property is present.
There are use cases at the periphery.

Use cases in bleeding edge JS include
* As you noted, operations on parsed JSON.  Even if you use revivers to parse JSON to Maps instead of Objects
  you either need own property checks or Object.setPrototypeOf(parsed, null) when populating the Map.  
* Non-clobbering mass assignment.  Like Object.assign but that doesn't overwrite existing properties in the assignee.
* Reliable hole detection in arrays: (1 !on [0, , 2])
* Adapters that use naming conventions between JS objects and external systems, like between database field names and JS property names.
* Distinguishing between user-code-defined properties on a host object like an HTML element and readonly host properties.

Many use cases for hasOwnProperty could be better supported by Map, Set, and Object.create(null) including:
* Objects used as lookup tables.
* Lookup tables with special purpose fallback logic like message bundles that fall back from locale 'aa-BB' to 'aa'.
* Configuration objects.
* Function options bundles.
but idiomatic JS hasn't caught up and some library code has to run on old interpreters, so a transpiling `on` would be nice.
The last two are mostly an issue in library code that needs to be resilient when loaded alongside monkeypatched prototypes.

Honorable mention:
* for(...in...) iteration broken
solved by for(...of...):


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