Small Proposal "!in"

Andy Earnshaw andyearnshaw at gmail.com
Thu Jul 19 13:54:33 UTC 2018


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 <mikesamuel at gmail.com> wrote:

> On Thu, Jul 19, 2018 at 7:32 AM Andy Earnshaw <andyearnshaw at gmail.com>
> 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 <tobias.buschor at shwups.ch>
>> 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 <
>>> mikesamuel at gmail.com>:
>>>
>>>>
>>>>
>>>> On Wed, Jul 18, 2018 at 12:21 PM Michael Theriot <
>>>> michael.lee.theriot at gmail.com> 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 <mikesamuel at gmail.com> wrote:
>>>>>
>>>>>>
>>>>>>
>>>>>> On Wed, Jul 18, 2018 at 11:05 AM Michael Theriot <
>>>>>> michael.lee.theriot at gmail.com> 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 <tobias.buschor at shwups.ch>
>>>>>>> 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
>>>>>>> es-discuss at mozilla.org
>>>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>>>
>>>>>> _______________________________________________
>>>> es-discuss mailing list
>>>> es-discuss at mozilla.org
>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>
>>>
>>>
>>> --
>>> Freundliche Grüsse
>>> Tobias Buschor
>>>
>>> schwups GmbH
>>> Hauptstr. 33
>>> 9424 Rheineck/SG
>>>
>>> +41 76 321 23 21 <+41%2076%20321%2023%2021>
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180719/6679cd71/attachment-0001.html>


More information about the es-discuss mailing list