Array.prototype.contains solutions

Mark S. Miller erights at google.com
Tue Sep 30 19:43:39 PDT 2014


On Tue, Sep 30, 2014 at 4:58 PM, Domenic Denicola <
domenic at domenicdenicola.com> wrote:

> This is a follow-up thread to discuss how to solve the problem identified
> in
> http://esdiscuss.org/topic/having-a-non-enumerable-array-prototype-contains-may-not-be-web-compatible
> without breaking the web. (Any arguments that it is OK to break sites using
> MooTools, please stay in that thread and respectfully do *not* reply to
> this one.)
>
> ---
>
> So, guess that proves I should never say "this will be easy!" before
> working on a feature. Yay, the web.
>
> I see a few options:
>
> 1. Rename. The leading candidate would be `Array.prototype.has`. I
> outlined in [1] why `contains` is better; note especially the DOM classes.
> But you could stretch things, especially by removing the `fromIndex`
> parameter, into an argument that `has` is OK. (Basically, you'd be saying
> that an array is more like a set than a map, and that its analogy with
> String is mostly accidental.)
>

If we do rename, it should be almost anything other than .has. Arrays are
clearly single-valued-mapping-like, not set-like, in that they map from
indexes to values. If Array.prototype.has were to exist, it would need to
test possible indexes.



>
> 2. Specific hacks. I am thinking of e.g. making `Array.prototype.contains`
> a getter, with a setter that does [[DefineOwnProperty]].
>

This could work, and it requires no new kernel mechanisms. If we do adopt
this solution, the setter should be careful to play the same games that SES
plays to work around the override mistake: If the this being set is not
Array.prototype itself, the setter should use [[DefineOwnProperty]] to
emulate an assignment to that this's own .contains.


>
> 3. General hacks. I joked about @@unMooToolsables, but seriously, we could
> do something similar to @@unscopables of using MOP hooks to fix this
> problem. One idea that seems reasonable is @@enumerableWhenAssigned, so
> that `Array.prototype.contains` starts non-enumerable, but when you do
> `Array.prototype.contains = x`, it becomes enumerable. You could even
> generalize this into something that also fixes the override mistake [2],
> e.g. @@defineOwnPropertyOnAssign or @@assignIgnoresProto or similar. Or you
> could attack the problem at the for-in level
>

I suggest we focus on the override mistake. If we come up with a way of
fixing it and .contains with one new kernel mechanism, that would be great.
If we only fix the override mistake, still likely worth it. But if a new
kernel mechanism only fixes .contains, it likely isn't worth it and we
should return to #1 or #2.




>
> ---
>
> 1 is tempting in its simplicity. 2 is pretty gross and we'd probably be
> better of throwing out the feature. 3 is intriguing, although it obviously
> adds complexity cost to a feature that was supposed to be trivial.
>
> I am curious if there is any support for 3, or proposals for a better hack
> in that vein. Because we will also have this problem for any other
> prototype extensions that work in the same way, e.g. MooTools's `flatten`
> (which seems like something we'd likely want) or their `associate`, `link`,
> `getRandom`, `combine`, or `pick` (which seem less likely). And I assume
> the problem could extend beyond MooTools, and possibly beyond Array.
> (Although, Array is a special case in that we can't make any of its methods
> enumerable.)
>
> Especially if we choose something more general, e.g. @@assignIgnoresProto,
> I could see this being a powerful tool for fighting such problems in the
> future, and maybe for helping fix the override mistake (although I don't
> understand all of the use cases involved there).
>
> [1]:
> https://github.com/domenic/Array.prototype.contains/#why-contains-instead-of-has
> [2]:
> http://wiki.ecmascript.org/doku.php?id=strawman:fixing_override_mistake


The most painful use case is the existence of perfectly reasonable ES5 code
like:


    function Point(x, y) { this.x = x; this.y = y; }

    Point.prototype.toString() { return `<${x},${y}>`; };

Because of the override mistake, this reasonable code no longer works after

    Object.freeze(Object.prototype);

This sucks.

SES goes out of its way to not break code that follows ES5 best practices.
The above Point code does. That's why SES's tamperProof(Object.prototype)
replaces the data properties on Object.prototype with accessor properties
whose setter uses [[DefineOwnProperty]] to emulate assignment on a this
that is not Object.prototype itself.

With your #3, perhaps we'd have a less painful way to working around the
override mistake.


>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>



-- 
    Cheers,
    --MarkM
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20140930/b4feff85/attachment-0001.html>


More information about the es-discuss mailing list