Array.prototype.contains

# Xavier MONTILLET (12 years ago)

harmony:string_extras There is a proposal for String.prototype.contains so why can't I find one for Array.prototype.contains?

.

# Jason Orendorff (12 years ago)

No kidding. I need this method every time I write ECMAScript code. What I want is like:

Object.defineProperty(Array.prototype, "contains", {
    configurable: true,
    writable: true,
    value: function contains(x) {
        return this.indexOf(x) !== -1;
    }
});

except without the property lookup for indexOf.

# Rick Waldron (12 years ago)

except without the property lookup for indexOf.

At this.indexOf ? Or the whole this.indexOf(x) !== -1; lookup? How else could it work?

# Brendan Eich (12 years ago)

Jason doesn't want a wrapper written in JS that depends on the current value of this.indexOf, I think. That's enough reason for a built-in. This is a no-brainer for ES6 IMHO.

# Rick Waldron (12 years ago)

That's what I figured - I guess I thinking of implementations that would be ES3 & 5 compat

# Greg Smith (12 years ago)

I see Array.contains as a great idea. This is an operation I use constantly when I write code and it'd be nice to have it be a first class Array operation. Sure it's not so different than indexOf, but the semantics are much more intuitive and it may very well be the more common operation.

# Greg Smith (12 years ago)

Sorry I meant Array.prototype.contains

# Erik Arvidsson (12 years ago)

DOM4 added a new interface called DOMStringList for the sole reason that Array does not have contains. Before this the return type was an Array of Strings so we could use indexOf, map, forEach etc. Now that it is using a non Array we lost all of that.

Proposal: Add Array.prototype.contains, implemented as:

Object.defineProperty(Array.prototype, 'contains', {
  value: function(value) {
    return this.indexOf(value) !== -1;
  },
  enumerable: false,
  configurable: true,
  writable: true
}{);

This is trivial enough to do in user code but since DOM4 depends on it we should just put it in the right place; In ES6.

# Domenic Denicola (12 years ago)

Perhaps using indexOfIdentical from harmony:simple_maps_and_sets

# Allen Wirfs-Brock (12 years ago)

Would it result in DOMStringList actually away?

# Mark S. Miller (12 years ago)

On Thu, Feb 23, 2012 at 12:18 PM, Domenic Denicola < domenic at domenicdenicola.com> wrote:

Perhaps using indexOfIdentical from harmony:simple_maps_and_sets

+1. If they want the behavior that's broken on -0.0 and NaN in the traditional way, I don't think that there's enough difference between saying

if (arr.contains(foo)) {

vs

if (arr.indexOf(foo) !== -1) {

to justify adding a new API, whether a new method or a new type. However, because fixing indexOf is not on the table, and I'd hate to introduce a parallel similar-but-different indexOfIdentical method as standard, if we're going to add any contains method as standard, it should not be similarly broken.

# Erik Arvidsson (12 years ago)

On Thu, Feb 23, 2012 at 12:23, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

Would it result in DOMStringList actually going away?

Yes. Since, with the addition of contains Array of String fully subsumes DOMStringList.

# Peter Michaux (12 years ago)

On Thu, Feb 23, 2012 at 12:35 PM, Mark S. Miller <erights at google.com> wrote:

if (arr.contains(foo)) {

vs

if (arr.indexOf(foo) !== -1) {

The readability of the above two options is very different. The first option is far superior as it expresses what the programmer wants to know. The second options is an expression of how it can be accomplished and requires understanding of indexOf's return values.

I think the addition Array.prototype.contains would be a good, simple one that would improve programs. The fact that this function exists in libraries means it is useful in a general in the opinion of at least several programmers.

Peter

# Mark S. Miller (12 years ago)

My point is that if we bother to add any contains method, that it shouldn't be broken the same way that indexOf is, making it an improvement over indexOf both in looks and in functionality. In other words, do you want

 [3.0, NaN, 4.0].contains(NaN)

to return false? I don't. I wish

[3.0, NaN, 4.0].indexOf(NaN)

didn't return -1, but it is now too late to fix that.

<only a bit tongue in cheek>

Think this kind of stupidity isn't dangerous? Here's a riddle: Say a JavaScript implementation, when asked to run the following program, instead kills the user. Does it conform to the spec?

[3.0, NaN, 4.0].sort(function compare(a, b) { return a < b ? -1 : a ===

b ? 0 : 1; })

When sorting a valid packed array of valid IEEE floating point values, you take your life in your hands. </only a bit tongue in cheek>

# Peter Michaux (12 years ago)

How about obsoleting indexOf, adding something better with a different name, and then building a contains method on top of that?

Peter

# Luke Hoban (12 years ago)

From: es-discuss-bounces at mozilla.org [mailto:es-discuss-bounces at mozilla.org] On Behalf Of Peter Michaux

On Thu, Feb 23, 2012 at 12:35 PM, Mark S. Miller <erights at google.com> wrote:

if (arr.contains(foo)) {

vs

if (arr.indexOf(foo) !== -1) {

The readability of the above two options is very different. The first option is far superior as it expresses what the programmer wants to know. The second options is an expression of how it can be accomplished and requires understanding of indexOf's return values.

I think the addition Array.prototype.contains would be a good, simple one that would improve programs. The fact that this function exists in libraries means it is useful in a general in the opinion of at least several programmers.

Given that we are also already adding String.prototype.contains [1] in ES6, Array.prototype.contains seems a natural extension to continue keeping Array and String helpers aligned for common operations that are meaningful on both. The argument to just use 'indexOf' would have been equally valid for String, but we had agreement that the usability/discoverability benefits of String.prototype.contains justified addition.

Luke

[1] harmony:string_extras

# Rick Waldron (12 years ago)

On Thu, Feb 23, 2012 at 3:15 PM, Erik Arvidsson <erik.arvidsson at gmail.com>wrote:

DOM4 added a new interface called DOMStringList for the sole reason that Array does not have contains. Before this the return type was an Array of Strings so we could use indexOf, map, forEach etc. Now that it is using a non Array we lost all of that.

Wouldn't the return type (or [[Class]]) still be restricted from using "Array"?

From 8.6.2

The value of the [[Class]] internal property is defined by this specification for every kind of built-in object. The value of the [[Class]] internal property of a host object may be any String value except one of "Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "Object", "RegExp", and "String".

So it can't be an "Array" by name, right?

(I'm not trying to be contrary, just looking for clarity :D )

# Erik Arvidsson (12 years ago)

On Fri, Feb 24, 2012 at 11:09, Rick Waldron <waldron.rick at gmail.com> wrote:

On Thu, Feb 23, 2012 at 3:15 PM, Erik Arvidsson <erik.arvidsson at gmail.com> wrote:

DOM4 added a new interface called DOMStringList for the sole reason that Array does not have contains. Before this the return type was an Array of Strings so we could use indexOf, map, forEach etc. Now that it is using a non Array we lost all of that.

Wouldn't the return type (or [[Class]]) still be restricted from using "Array"?

No. We (WebKit) used to return a true JS Array (created by JSC or V8).

# Allen Wirfs-Brock (12 years ago)

On Feb 24, 2012, at 11:09 AM, Rick Waldron wrote:

On Thu, Feb 23, 2012 at 3:15 PM, Erik Arvidsson <erik.arvidsson at gmail.com> wrote: DOM4 added a new interface called DOMStringList for the sole reason that Array does not have contains. Before this the return type was an Array of Strings so we could use indexOf, map, forEach etc. Now that it is using a non Array we lost all of that.

Wouldn't the return type (or [[Class]]) still be restricted from using "Array"?

From 8.6.2

The value of the [[Class]] internal property is defined by this specification for every kind of built-in object. The value of the [[Class]] internal property of a host object may be any String value except one of "Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "Object", "RegExp", and "String".

So it can't be an "Array" by name, right?

It can be, as long as it really is a ES array. "host object" doesn't mean any object created by the host. It means new kinds of objects created by the host that implement primitive behaviors (generally internal methods) differently from what is specified by the ES spec.

So, from the ES perspective, no problem. When I originally asked the question I was thinking more about from the Web IDL perspective. Does Web IDL require things (for example throwing if extra arguments are passed) that ES Arrays do not do.

# Rick Waldron (12 years ago)

Allen, thank you for the clarification there

# Joshua Bell (11 years ago)

Bump.

I don't think Array.prototype.contains ever materialized on the "proposals" page, and hasn't shown up in an ES6 draft.

Officially out for ES6, stuck in the queue, or dropped on the floor?

# Allen Wirfs-Brock (11 years ago)

On Nov 1, 2012, at 11:04 AM, Joshua Bell wrote:

Bump.

I don't think Array.prototype.contains ever materialized on the "proposals" page, and hasn't shown up in an ES6 draft.

Officially out for ES6, stuck in the queue, or dropped on the floor?

Probably dropped on the floor, unless somebody can find something about it in meeting notes.

It looks to me from scanning just this thread that it was an idea that was floated here with generally positive responses, but had some unresolved issues, and nobody ever signed on as champion to write an actual proposal.

# Erik Arvidsson (11 years ago)

I'll put up a proposal once electricity is back. I'll use the same comparison as done in maps.

# Allen Wirfs-Brock (11 years ago)

There is also the compat issue with Mootools with String contains...

If we decided we needed to rename String contains then it might also impact what we call a similar Array method

# Rick Waldron (11 years ago)

On Fri, Nov 2, 2012 at 11:25 AM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

There is also the compat issue with Mootools with String contains...

If we decided we needed to rename String contains then it might also impact what we call a similar Array method

Perhaps it should be "has" instead of "contains"? Consistent with the other "collections".

# Mark S. Miller (11 years ago)

On Fri, Nov 2, 2012 at 8:19 AM, Erik Arvidsson <erik.arvidsson at gmail.com>wrote:

I'll put up a proposal once electricity is back. I'll use the same comparison as done in maps.

With it being the same comparison as maps (which use SameValue), +1. Note that this makes contains/has inconsistent with indexOf (which uses ===).

I also support calling it "has" as Rick suggests. Perhaps this also helps suggest that it is like the other "has"s, which use SameValue, and not like indexOf.

(I am still sad we did not fix indexOf, lastIndexOf, and switch when we arguably had the chance.)

# Andrea Giammarchi (11 years ago)

I was wondering the same ... if contains() is the new indexOf then why other collections are using has() ... I like has() more but it might be me lazy typer ... still it should be consistent.

# Erik Arvidsson (11 years ago)

On Fri, Nov 2, 2012 at 12:30 PM, Mark S. Miller <erights at google.com> wrote:

I also support calling it "has" as Rick suggests. Perhaps this also helps suggest that it is like the other "has"s, which use SameValue, and not like indexOf.

(I am still sad we did not fix indexOf, lastIndexOf, and switch when we arguably had the chance.)

If we call it "has", should we also rename String.prototype.contains?

# Rick Waldron (11 years ago)

On Fri, Nov 2, 2012 at 1:20 PM, Erik Arvidsson <erik.arvidsson at gmail.com>wrote:

On Fri, Nov 2, 2012 at 12:30 PM, Mark S. Miller <erights at google.com> wrote:

I also support calling it "has" as Rick suggests. Perhaps this also helps suggest that it is like the other "has"s, which use SameValue, and not like indexOf.

(I am still sad we did not fix indexOf, lastIndexOf, and switch when we arguably had the chance.)

If we call it "has", should we also rename String.prototype.contains?

Blitzed! I was just drafting a reply asking the same thing.

I think for consistency, yes... Although I'm not sure about using SameValue

# Andrea Giammarchi (11 years ago)

+1 ... but funny that for Strings I would naturally use "mychunk" in mystring rather than mystring.has("mychunk") .... I believe contains comes from XSL, isn't it? Was it W3C suggestion or what?

# Domenic Denicola (11 years ago)

-----Original Message----- From: es-discuss-bounces at mozilla.org [mailto:es-discuss-bounces at mozilla.org] On Behalf Of Erik Arvidsson Sent: Friday, November 2, 2012 13:21

If we call it "has", should we also rename String.prototype.contains?

I'd say no; the distinction between collections "having" an element and strings "containing" a substring seems very sensible. It's a bit more awkward to say a string "has" a substring, and a string is definitely not a collection of substrings in any reasonable sense.

If anyone had proposed String.prototype.has(singleCharOrMaybeCodePoint), then perhaps that name would make sense.

# Joshua Bell (11 years ago)

On Fri, Nov 2, 2012 at 9:14 AM, Rick Waldron <waldron.rick at gmail.com> wrote:

On Fri, Nov 2, 2012 at 11:25 AM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

There is also the compat issue with Mootools with String contains...

If we decided we needed to rename String contains then it might also impact what we call a similar Array method

Perhaps it should be "has" instead of "contains"? Consistent with the other "collections".

If you dig back far enough in this thread [1], you'll see that one of the motivations for suggesting this was to be able to obsolete DOMStringList [2] and quietly switch existing methods to returning plain old Arrays. That would argue for keeping the name as "contains".

But given that DOMStringList also has an explicit "items" method, and the implications of the restriction to strings - e.g. calling d.contains(1) or d.contains(undefined) follow WebIDL rules for stringifying the argument - it is probably too late to actually remove DOMStringList from the platform.

[1] esdiscuss/2012-February/020726 [2] www.w3.org/TR/DOM-Level-3-Core/core.html#DOMStringList

# Jason Orendorff (11 years ago)

On Fri, Nov 2, 2012 at 12:29 PM, Domenic Denicola < domenic at domenicdenicola.com> wrote:

If we call it "has", should we also rename String.prototype.contains?

I'd say no; the distinction between collections "having" an element and strings "containing" a substring seems very sensible. It's a bit more awkward to say a string "has" a substring, and a string is definitely not a collection of substrings in any reasonable sense.

Well, you could also note that array.has(x) looks for a particular value, while map.has(x) looks for a particular key.

But that's not the point. There's no common formal contract implemented by all these methods; what they share is an informal "hey, look in this thing, and tell me if you see that thing" vibe.

I like the idea of being able to say str.has(",") or str.has("=>") or

str.has("@jorendorff") and have them all just work.

# Rick Waldron (11 years ago)

On Friday, November 2, 2012 at 1:56 PM, Jason Orendorff wrote:

On Fri, Nov 2, 2012 at 12:29 PM, Domenic Denicola <domenic at domenicdenicola.com (mailto:domenic at domenicdenicola.com)> wrote:

If we call it "has", should we also rename String.prototype.contains?

I'd say no; the distinction between collections "having" an element and strings "containing" a substring seems very sensible. It's a bit more awkward to say a string "has" a substring, and a string is definitely not a collection of substrings in any reasonable sense.

Well, you could also note that array.has(x) looks for a particular value, while map.has(x) looks for a particular key.

But that's not the point. There's no common formal contract implemented by all these methods; what they share is an informal "hey, look in this thing, and tell me if you see that thing" vibe.

I like the idea of being able to say str.has(",") or str.has("=>") or str.has("@jorendorff") and have them all just work.

This is definitely nice :)

Jason, Erik, Mark,

Any specific thoughts about the SameValue case as it likely doesn't apply to a hypothetical String.prototype.has impl.? I suspect that a string had would still use indexOf which would introduce an internal inconsistency for the sake of API consistency (which I'm all for). Unless I'm overlooking?

# Erik Arvidsson (11 years ago)
# Mark S. Miller (11 years ago)

Fortunately, strings cannot contain -0.0 or NaN, so neither string.contains nor string.has sets any relevant precedent. FWIW, neither does string.indexOf nor string.lastIndexOf.

The only consistency issue is: should array.has agree with sense and all other collections, or should it agree with array.indexOf / lastIndexOf. FWIW, I would prefer not to add any more conveniences that further entrench unexpected === checks.

[NaN].has(NaN) // false

makes little sense.

[0.0].has(-0.0) // true

makes somewhat more sense, but not enough. Please let's either use add "has" using SameValue or not add anything at all.

# David Herman (11 years ago)

On Nov 2, 2012, at 11:55 AM, Mark S. Miller <erights at google.com> wrote:

The only consistency issue is: should array.has agree with sense and all other collections, or should it agree with array.indexOf / lastIndexOf. FWIW, I would prefer not to add any more conveniences that further entrench unexpected === checks.

[NaN].has(NaN) // false

makes little sense.

[0.0].has(-0.0) // true

makes somewhat more sense, but not enough. Please let's either use add "has" using SameValue or not add anything at all.

Sorry to complicate the opinion landscape further, but I'm not convinced that any collections should be using SameValue. Looking over my personal notes from an earlier conversation Mark and I had about maps and sets, I think we came to something where the default equivalence should be the tightest possible one (SameValue), but it should be possible to provide your own equality predicate as an optional constructor argument. We don't have that option for arrays.

There are plenty of operations that can result in a -0 without the programmer being aware, such as Math functions. I shudder to imagine debugging a program like this:

[Math.round(-0.1)].has(0) // false!

I agree that NaN should be equated, but I'm pretty nervous about the idea of distinguishing 0 and -0, especially when there's no way to override that behavior.

# Asen Bozhilov (11 years ago)

Erik Arvidsson

If we call it "has", should we also rename String.prototype.contains?

Most of the JS libraries use has method for checking property and key existence. I am wondering if there is Array.prototype.has how they would overload their has methods to work as expected with arrays, array-like and regular native objects. Also their is and Object.prototype.hasOwnProperty. For example this code is a little bit confusing for me:

var arr = [1, 2, 3]; arr.hasOwnProperty(0); //true arr.has(0); //false

# Brendan Eich (11 years ago)

David Herman wrote:

 [Math.round(-0.1)].has(0) // false!

Could be a problem, but my position is that anyone using Math.round has to deal with -0. It is observably different from 0 via other Math functions, even if ===.

# Allen Wirfs-Brock (11 years ago)

On Nov 2, 2012, at 10:56 AM, Jason Orendorff wrote:

On Fri, Nov 2, 2012 at 12:29 PM, Domenic Denicola <domenic at domenicdenicola.com> wrote:

If we call it "has", should we also rename String.prototype.contains?

I'd say no; the distinction between collections "having" an element and strings "containing" a substring seems very sensible. It's a bit more awkward to say a string "has" a substring, and a string is definitely not a collection of substrings in any reasonable sense.

Well, you could also note that array.has(x) looks for a particular value, while map.has(x) looks for a particular key.

But that's not the point. There's no common formal contract implemented by all these methods; what they share is an informal "hey, look in this thing, and tell me if you see that thing" vibe.

There is no verifiable formal contract. But there can be an informal contract. In my experience, it is very important when using a dynamic language to recognize and try to support such informal contracts.

All the uses of "has" we have defined so far are about the "keys". Having one place that is about the "values" to create unnecessary confusion

Note that we (the JS/ES designers) already have a history of being being inconsistent in our use of names. Consider String indexOf and Array indexOf they are named the same and appear to have signatures. But they logically are doing quite different things. String indexOf is looking for the index of the first element of a subsequence of character elements that matches a specific character sequence. Array indexOf is looking for the index of a single element that contains a specific value. You might want to implement a logically similar subsequence search for Array's but if you do, you can't call it indexOf because that name was already used for something with different semantics. We should try to do better as people for our example.

# Andrea Giammarchi (11 years ago)

I actually agree on this, but Set.has() is misleading then, imho. Shouldn't be specified that has() is key related and contains() is value related? Also a "magic" Object.has(obj, key) with smart obj recognition and Object.contains(obj, value) would be probably cool

# Brendan Eich (11 years ago)

Allen Wirfs-Brock wrote:

On Nov 2, 2012, at 10:56 AM, Jason Orendorff wrote:

On Fri, Nov 2, 2012 at 12:29 PM, Domenic Denicola <domenic at domenicdenicola.com <mailto:domenic at domenicdenicola.com>> wrote:

> If we call it "has", should we also rename
String.prototype.contains?

I'd say no; the distinction between collections "having" an
element and strings "containing" a substring seems very sensible.
It's a bit more awkward to say a string "has" a substring, and a
string is definitely not a collection of substrings in any
reasonable sense.

Well, you could also note that array.has(x) looks for a particular value, while map.has(x) looks for a particular key.

But that's not the point. There's no common formal contract implemented by all these methods; what they share is an informal "hey, look in this thing, and tell me if you see that thing" vibe.

There is no verifiable formal contract. But there can be an informal contract. In my experience, it is very important when using a dynamic language to recognize and try to support such informal contracts.

All the uses of "has" we have defined so far are about the "keys". Having one place that is about the "values" to create unnecessary confusion

Note that we (the JS/ES designers) already have a history of being being inconsistent in our use of names. Consider String indexOf and Array indexOf

stackoverflow.com/questions/4962361/where-is-javas-array-indexof

they are named the same and appear to have signatures. But they logically are doing quite different things. String indexOf is looking for the index of the first element of a subsequence of character elements that matches a specific character sequence. Array indexOf is looking for the index of a single element that contains a specific value. You might want to implement a logically similar subsequence search for Array's but if you do, you can't call it indexOf because that name was already used for something with different semantics. We should try to do better as people for our example.

That one never bugged me, and I suppose one could "fix" it by allowing by-value search for a sub-array from Array.prototype.indexOf. I've never seen anyone do that.

"has" for keys (and possibly values of a Set, to preserve the value mapped to boolean future option that forEach also supports), "contains" for values in arrays?

# Brendan Eich (11 years ago)

Andrea Giammarchi wrote:

I actually agree on this, but Set.has() is misleading then, imho. Shouldn't be specified that has() is key related and contains() is value related?

The forEach signature has (value, key, collection), and for a Set is called with (value, value, theSet). We discussed this at the Boston f2f and recently on list. It allows us to extend Sets in the future (under object model reformation, e.g.) to map value to boolean has-result.

Apart from the Set special case, using contains for values and has for keys seems better and better to me. But that means String.prototype.contains, not has. The test is for values, not keys, in that case. Same thing with Array.prototype.contains (and MooTools must adapt).

# Allen Wirfs-Brock (11 years ago)

On Nov 2, 2012, at 4:54 PM, Brendan Eich wrote:

Allen Wirfs-Brock wrote:

... Note that we (the JS/ES designers) already have a history of being being inconsistent in our use of names. Consider String indexOf and Array indexOf

stackoverflow.com/questions/4962361/where-is-javas-array-indexof

they are named the same and appear to have signatures. But they logically are doing quite different things. String indexOf is looking for the index of the first element of a subsequence of character elements that matches a specific character sequence. Array indexOf is looking for the index of a single element that contains a specific value. You might want to implement a logically similar subsequence search for Array's but if you do, you can't call it indexOf because that name was already used for something with different semantics. We should try to do better as people for our example.

That one never bugged me, and I suppose one could "fix" it by allowing by-value search for a sub-array from Array.prototype.indexOf. I've never seen anyone do that.

It never bothered me either up to now. Probably because we usually don't think about JS strings as a "collections" (immutable array of uint16s) all that much. But if you starting thinking about strings as a kind of collection and look for uniformity in collection interfaces, indexOf stands out as being problematic.

"has" for keys (and possibly values of a Set, to preserve the value mapped to boolean future option that forEach also supports), "contains" for values in arrays

sounds ok, except we get the same issue for contains that we have for indexOf. II guess the big thing with contains is that it can be applied no non-indexed collections (maps, sets, etc.).

Also any reason contains should be provided for WeakMap? I not seeing why it shouldn't be there too.

# Brendan Eich (11 years ago)

Allen Wirfs-Brock wrote:

"has" for keys (and possibly values of a Set, to preserve the value mapped to boolean future option that forEach also supports), "contains" for values in arrays

sounds ok, except we get the same issue for contains that we have for indexOf. II guess the big thing with contains is that it can be applied no non-indexed collections (maps, sets, etc.).

I'm not sure there's enough of a problem with using contains (or indexOf) to justify splitting contains-names, which has its own problems (inconsistency with indexOf, also with other languages, mutatis mutandis, e.g. Java).

Also any reason contains should be provided for WeakMap? I not seeing why it shouldn't be there too.

How about Map contains (as well as has)?

How about Set for that matter?

# Allen Wirfs-Brock (11 years ago)

On Nov 2, 2012, at 5:45 PM, Brendan Eich wrote:

Allen Wirfs-Brock wrote:

"has" for keys (and possibly values of a Set, to preserve the value mapped to boolean future option that forEach also supports), "contains" for values in arrays

sounds ok, except we get the same issue for contains that we have for indexOf. II guess the big thing with contains is that it can be applied no non-indexed collections (maps, sets, etc.).

I'm not sure there's enough of a problem with using contains (or indexOf) to justify splitting contains-names, which has its own problems (inconsistency with indexOf, also with other languages, mutatis mutandis, e.g. Java).

me neither...just a wart

Also any reason contains should be provided for WeakMap? I not seeing why it shouldn't be there too.

How about Map contains (as well as has)?

How about Set for that matter?

Because people might actually use Map contains not realizing it isn't a near constant time probe like has. But, that concern is offset by the disability of having a consistent set of collection interfaces plus we don't like being a nannies.

I'd probably be on board with with having both for Set/Map/WeakMap

# Axel Rauschmayer (11 years ago)

+1

I have always found Java’s collection API fairly intuitive. It could serve as a role model, at least partially.

  • Map: containsKey, containsValue
  • Set: contains

Note that it has an isEmpty() method. I would also want to have its methods for combining collections such as removeAll() and retainAll().

docs.oracle.com/javase/6/docs/api/java/util/Map.html, docs.oracle.com/javase/6/docs/api/java/util/Set.html

[[[Sent from a mobile device. Please forgive brevity and typos.]]]

Dr. Axel Rauschmayer axel at rauschma.de Home: rauschma.de Blog: 2ality.com

# Rick Waldron (11 years ago)

On Fri, Nov 2, 2012 at 9:55 PM, Axel Rauschmayer <axel at rauschma.de> wrote:

+1

I have always found Java’s collection API fairly intuitive. It could serve as a role model, at least partially.

  • Map: containsKey, containsValue

I'd rather see Set.prototype.values() defined for Map.prototype

  • Set: contains

Note that it has an isEmpty() method.

.size get-accessor property, which will be 0 if it's empty. I honestly believe in api growth should address a need, if this turns out to be a pain point, then we should consider it for Collection extras in ES7, but I've never seen anyone extend Array.prototype with an isEmpty method. There are user land implementations of isEmpty() and isEmptyObject() that are used to make up for Object.prototype not having any way of determining if there are any own-enumerable properties.

var o = {};

isEmpty(o); // true

o.p = 1;

isEmpty(o); // false

but Map and Set shouldn't need anything like this, because like Array, they have a mechanism for disclosing "how many things I have"

I would also want to have its methods for combining collections such as removeAll() and retainAll().

A more generic .filter() method would allow user code to create these methods if the need was sufficient.

# Mark S. Miller (11 years ago)

On Fri, Nov 2, 2012 at 5:26 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

Also any reason contains should be provided for WeakMap? I not seeing why it shouldn't be there too.

Yes!

The set of values actually contained by the WeakMap at any moment is non-deterministic, depending on the scheduling of gc. But this non-determinism is non-observable. WeakMap.contains would make it observable.

# Allen Wirfs-Brock (11 years ago)

On Nov 3, 2012, at 4:53 PM, Mark S. Miller wrote:

On Fri, Nov 2, 2012 at 5:26 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

Also any reason contains should be provided for WeakMap? I not seeing why it shouldn't be there too.

Yes!

The set of values actually contained by the WeakMap at any moment is non-deterministic, depending on the scheduling of gc. But this non-determinism is non-observable. WeakMap.contains would make it observable.

yup

# Brendan Eich (11 years ago)

Is this true? I can see how enumeration and size would leak the GC schedule, but to test has or contains, you need a strong ref, which means the key or value cannot yet be garbage. If you have the capability, there's no non-determinism. What am I missing?

# Mark S. Miller (11 years ago)

WeakMap.has is fine (and already speced) because the presence of the association depends on the key. However, if the key is garbage, a strong ref to the value does not preserve the association in the map.

# Brendan Eich (11 years ago)

Mark S. Miller wrote:

WeakMap.has is fine (and already speced) because the presence of the association depends on the key. However, if the key is garbage, a strong ref to the value does not preserve the association in the map.

Right! Thanks.

# Axel Rauschmayer (11 years ago)

(I am still sad we did not fix indexOf, lastIndexOf, and switch when we arguably had the chance.)

Can you elaborate? We don’t have the chance, any more? Would anything break (or did, in tests)? How about only letting those methods find NaN, while letting them consider +0 and -0 equal?

Axel

# Mark S. Miller (11 years ago)

On Sat, Nov 3, 2012 at 10:13 PM, Axel Rauschmayer <axel at rauschma.de> wrote:

(I am still sad we did not fix indexOf, lastIndexOf, and switch when we arguably had the chance.)

Can you elaborate? We don’t have the chance, any more? Would anything break (or did, in tests)?

I am not aware of anyone gathering any evidence one way or the other about what breakage this might cause. So it is not necessarily too late. If someone does gather actual evidence that the breakage would be small enough, I could see us reconsider this. But I doubt we would revisit in the absence of such evidence.

How about only letting those methods find NaN, while letting them consider +0 and -0 equal?

In one way, that would be a big improvement on the status quo: such a rule would still form an equivalence class. (By contrast, === does not form an equivalence class since it is not reflexive.)

OTOH, it would make for yet a fourth built-in equality-like test. I don't think the payoff is worth the complexity.

# Claus Reinke (11 years ago)

The set of values actually contained by the WeakMap at any moment is non-deterministic, depending on the scheduling of gc. But this non-determinism is non-observable. WeakMap.contains would make it observable.

a) this concise elaboration should be part of the spec, to reduce guessing about the design intentions

b) there is at least one use case where observing gc would be useful: instrumenting code for heap profiling;

since built-in heap profiling is supported in too few JS debuggers 
atm, I was wondering whether there could be some reflection-
level language support for "this object is no longer referenced",
perhaps as an iterator for WeakMap; then tool builders could 
use that, and standard users would be aware that this isn't a
normal-level feature.

Claus

# Jason Orendorff (11 years ago)

On Sun, Nov 4, 2012 at 3:58 AM, Claus Reinke <claus.reinke at talk21.com>wrote:

The set of values actually contained by the WeakMap at any moment is

non-deterministic, depending on the scheduling of gc. But this non-determinism is non-observable. WeakMap.contains would make it observable.

a) this concise elaboration should be part of the spec, to reduce guessing about the design intentions

Definitely worth a note.

b) there is at least one use case where observing gc would be

useful: instrumenting code for heap profiling; [...]

Firefox has a function, Components.utils.nonDeterministicGetWeakMapKeys(weakmap), that can observe GC in this way. Only privileged code (the browser itself, addons, and certain tests) can use it. Web scripts can't.

When implementation details get exposed as part of a platform, programs start depending (often unintentionally) on them. Let's not expose memory management implementation details to the Web.

# Jeff Walden (11 years ago)

On 11/03/2012 11:06 PM, Mark S. Miller wrote:

On Sat, Nov 3, 2012 at 10:13 PM, Axel Rauschmayer <axel at rauschma.de <mailto:axel at rauschma.de>> wrote:

(I am still sad we did not fix indexOf, lastIndexOf, and switch when we arguably had the chance.)
Can you elaborate? We don’t have the chance, any more? Would anything break (or did, in tests)?

I am not aware of anyone gathering any evidence one way or the other about what breakage this might cause. So it is not necessarily too late. If someone does gather actual evidence that the breakage would be small enough, I could see us reconsider this. But I doubt we would revisit in the absence of such evidence.

Just to note, there was a (at least this one) long thread on the topic (well, not including switch -- I don't remember a thread that considered changing switch) back in the day, if someone's invested enough in this to read it.

mail.mozilla.org/pipermail/es5-discuss/2009-August/003006.html

# Jason Orendorff (11 years ago)

On Fri, Nov 2, 2012 at 4:30 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

There is no verifiable formal contract. But there can be an informal contract. In my experience, it is very important when using a dynamic language to recognize and try to support such informal contracts.

Well, I sort of agree. But even Ruby, as much as it owes to Smalltalk, provides same-named methods in Array and Hash with completely incompatible semantics. Hash»delete takes a key argument; Array»delete takes a value. Array»each yields values; Hash»each yields key-value pairs. I expect this is just because the operations you need from an Array vs. a Hash are really different in practice. Their abstract conceptual similarity doesn't seem to make the jump to the real world.

Returning to JS: is there really an informal contract that unifies Array, Map, and strings? In the current spec, there's not a single method that works the same way across all three!

The only thing that even exists across all three is .@@iterator(), which is no small thing. But note that Array.prototype.@@iterator yields element values, String.prototype.@@iterator yields UTF-16-encoded characters, and Map.prototype.@@iterator yields key-value pairs.

A common protocol could certainly be added. For the sake of concreteness: they could all have .hasKey(k), .hasValue(v), .get(k), .size, .keys(), .values(), .items(), .forEach(f); and on mutable collections, .set(k, v), .delete(k), .clear(). But I think the aesthetic appeal of this sort of thing is way out of proportion to its practical value.

# Eric Elliott (10 years ago)

What ever happened to Array.prototype.contains? There's an old strawman for Array.prototype.has that references this thread: esdiscuss/2012-February/020745

But it seems the thread fizzled out a couple years ago, and Array.prototype.contains didn't seem to make its way into ES6. That seems odd, since we do have String.prototype.contains, and it seemed like it was desirable for DOM. It's also a standard utility function in several libraries.

Was it left out on purpose? If so, what was the justification?

I predict code like this without it:

''.contains.call([1, 2, 3], 2);  // true
# David Bruant (10 years ago)

Le 05/03/2014 09:24, Eric Elliott a écrit :

What ever happened to Array.prototype.contains?

Let's try to add it to the next meeting agenda tc39/agendas#27

it seemed like it was desirable for DOM.

The DOM won't inherit from it directly, shall it?

I predict code like this without it:

''.contains.call([1,2,3],2);// true

.indexOf === -1 works today for this use case and will continue to. I'd be happy to see !~arr.indexOf(el) disappear in favor of a use of .contains() though.

# Eric Elliott (10 years ago)

According to the thread:

On Thu, Feb 23, 2012 at 3:15 PM, Erik Arvidsson wrote:

DOM4 added a new interface called DOMStringList for the sole reason that Array does not have contains. Before this the return type was an Array of Strings so we could use indexOf, map, forEach etc. Now that it is using a non Array we lost all of that.

We (WebKit) used to return a true JS Array (created by JSC or V8).

# Sebastian Zartner (10 years ago)

The DOM won't inherit from it directly, shall it?

Why not? A use case would be to check whether a specific node is within a NodeList.

.indexOf === -1 works today for this use case and will continue to. I'd be happy to see !~arr.indexOf(el) disappear in favor of a use of .contains() though.

While .indexOf() just gets you the index of one item, .contains() could even be extended to allow to check whether an array contains several items. E.g.

.contains([1, 2, 3], [1, 3]) // true
.contains([1, 2, 3], [1, 4]) // false
# Boris Zbarsky (10 years ago)

On 3/5/14 7:04 AM, Sebastian Zartner wrote:

Why not? A use case would be to check whether a specific node is within a NodeList.

NodeLists don't have have Array.prototype on their proto chain in browsers at the moment, and might never get there; there are compat concerns.

I'd love to get rid of DOMStringList, though.

# Rick Waldron (10 years ago)

On Wed, Mar 5, 2014 at 4:07 AM, David Bruant <bruant.d at gmail.com> wrote:

The DOM won't inherit from it directly, shall it?

The forth-coming-still-in-design "Elements" class will inherit from Array.

# Rick Waldron (10 years ago)

On Wed, Mar 5, 2014 at 7:04 AM, Sebastian Zartner <sebastianzartner at gmail.com> wrote:

While .indexOf() just gets you the index of one item, .contains() could even be extended to allow to check whether an array contains several items. E.g.

.contains([1, 2, 3], [1, 3]) // true
.contains([1, 2, 3], [1, 4]) // false

String.prototype.contains already has a second parameter for "position" (similar to String.prototype.indexOf), for consistency an Array.prototype.contains should have the same second "fromIndex" parameter as Array.prototype.indexOf.

# Domenic Denicola (10 years ago)

Personally I think the more useful model to follow than String.prototype.contains is Set.prototype.has.

# Rick Waldron (10 years ago)

Now that you mention it, I completely agree.

# C. Scott Ananian (10 years ago)

Hmm:

s = new Set(['a','b','c']);
s.has('a'); // true
s.has('ab'); // false

s = "abc";
s.contains("a"); // true
s.contains("ab"); // true
s.contains("ab", 1); // false

s = [ 'a', 'b', 'c' ];
s.has('a'); // true
s.has('ab'); // false

s.contains('a'); // true
s.contains('b', 1); // false? like String#contains
// what sebastian wants?
s.contains('a', 'b'); // true?
s.contains(...new Set(['a','b'])); // if the above works, so does this

s.has(...new Set(['a','b'])); // better?
# Mathias Bynens (10 years ago)

On 5 Mar 2014, at 17:19, Domenic Denicola <domenic at domenicdenicola.com> wrote:

Personally I think the more useful model to follow than String.prototype.contains is Set.prototype.has.

But then DOM4 DOMStringList would still have its own contains and the has it inherits from Array.prototype. That seems confusing, no?

# Anne van Kesteren (10 years ago)

On Wed, Mar 5, 2014 at 11:19 PM, Domenic Denicola <domenic at domenicdenicola.com> wrote:

Personally I think the more useful model to follow than String.prototype.contains is Set.prototype.has.

That would not allow us to kill DOMStringList.

# Domenic Denicola (10 years ago)

Can we get more background on DOMStringList? It seems unlikely that you could get away with replacing a string-only type, which, from the specs I can find, seems to be immutable and have an additional index() method, with an actual mutable any-type-containing array.

It's not in dom.spec.whatwg.org (except as "don't implement this") and developer.mozilla.org/en-US/docs/Web/API/DOMStringList implies it's not implemented in Mozilla, and only used by an obscure property.

# Boris Zbarsky (10 years ago)

On 3/6/14 3:58 PM, Domenic Denicola wrote:

Can we get more background on DOMStringList?

Sure. It's used in the following places in Gecko, as far as I can tell:

  1. document.styleSheetSets.
  2. Microdata API.
  3. Various places in indexeddb.
  4. The DataTransfer API.
  5. Some sort of offline resource list API that's not part of any standard I can find.

#1 is not implemented by anyone but Gecko, and the spec is claiming it's a DOMString[], which no on implements at all.

#2 is likewise not implemented by anyone but Gecko at this point, and the spec likewise claims DOMString[] (which again no one implements).

For #3 I've heard Jonas claim he'd like to just moving ES arrays there.

#4 is specced as a DOMString[], which again no one implements.

I don't know offhand what other UAs do for #3 and #4.

It seems unlikely that you could get away with replacing a string-only type, which, from the specs I can find, seems to be immutable and have an additional index() method

DOMStringList in Gecko does not have an index() method. Did you mean item()?

Whether it's OK to replace with a mutable and any-type-containing thing is an interesting philosophical question. Some of the above use cases may be OK with using a frozen array, for example, or not care if the page changes it around, since the browser doesn't plan to use it itself.

But yes, it's not a priori obvious that one can replace the other.

developer.mozilla.org/en-US/docs/Web/API/DOMStringList implies it's not implemented in Mozilla

That page was a bald-faced lie. Note the "in need of a technical review" bit. ;) I've removed the completely bogus part for now.

# Domenic Denicola (10 years ago)

Thanks very much Boris. It sounds like there isn't much of a cross-browser or standardized story on where DOMStringList, with its contains() and item() methods (yeah, I meant item) shows up.

I'd be curious where it shows up in Blink, IE, and WebKit codebases. If the intersection is small enough, such that no web developers are relying on contains() and item() being present on certain APIs, then maybe DOMStringList can be killed and replaced with arrays and/or frozen arrays, without adding contains()/item() to Array.prototype...

# Brendan Eich (10 years ago)

Boris Zbarsky wrote:

#1 is not implemented by anyone but Gecko, and the spec is claiming it's a DOMString[], which no on implements at all.

#2 is likewise not implemented by anyone but Gecko at this point, and the spec likewise claims DOMString[] (which again no one implements).

For #3 I've heard Jonas claim he'd like to just moving ES arrays there.

#4 is specced as a DOMString[], which again no one implements.

What's with all the "no one implements" (including #3) stuff in specs? Are the specs new? Are we in a situation (even in #3, pace Jonas) where the specs should be changed to reflect reality?

# Boris Zbarsky (10 years ago)

On 3/6/14 4:49 PM, Brendan Eich wrote:

What's with all the "no one implements" (including #3) stuff in specs?

IDL Arrays in general are not implemented by anyone that I know of (and possibly ever). They were a new concept added in WebIDL that hasn't really caught on with implementations. In Gecko's case that was because we never got around to it, and it was simpler to use the infrastructure we needed to create anyway or already had for "indexed getters" (c.f. DOMStringList, NodeList, etc) than to create a bunch of new infrastructure for IDL Arrays.

And then people realized that in some ways IDL Arrays are an attractive nuisance even if they were implemented, which made the priority on implementing them even less.

www.w3.org/Bugs/Public/show_bug.cgi?id=23682 has discussion that's worth reading, if people haven't already, about the various use cases that arise for arrays and arraylikes and how to best solve them.

Are the specs new?

Somewhat.

Are we in a situation (even in #3, pace Jonas) where the specs should be changed to reflect reality?

Yes. Need to figure out what reality is or should be, first.

# Joshua Bell (10 years ago)

FWIW, Blink uses DOMStringList only in IndexedDB and apparently in Location.ancestorOrigins

# C. Scott Ananian (10 years ago)

And don't forget the related DOMTokenList, which is in Element.classList and thus used by everyone always.

The contains and item methods are in DOMTokenList, so they probably shouldn't be removed from DOMStringList. But I don't think anyone was seriously proposing that, just that DOMStringList would be a subclass of Array... (and maybe DOMTokenList would also be related to Array?)

# Claude Pache (10 years ago)

Le 7 mars 2014 à 00:45, C. Scott Ananian <ecmascript at cscott.net> a écrit :

And don't forget the related DOMTokenList, which is in Element.classList and thus used by everyone always.

Indeed, and there is also the (less known) htmlFor property of the <output> element, which is precisely a DOMSettableTokenList.

Since arraylike interfaces from the DOM uses .contains(), for the sake of consistency, the corresponding method on Array.prototype ought to be named .contains(). Sets are quite different from Arrays, so it is less important to have the same naming scheme as Sets than as all other arraylikes. (And another weaker reason to prefer .contains(): Maps and WeakMaps uses .has() for keys, and here we are talking about the values of an Array.)

# medikoo (10 years ago)

Domenic Denicola-2 wrote

Personally I think the more useful model to follow than String.prototype.contains is Set.prototype.has.

API wise, arrays have much more in common with strings than with sets.

Thinking ES5, they're both array-likes, set isn't. They share length property, their values can be accessed through indexes arr[0], str[0], they share few method names (indexOf, lastIndexOf), and all non destructive array methods can be successfully executed on strings, while they won't work with sets.

I think it would be more appropriate to stick with arr.contains especially that we already have arr.indexOf and str.indexOf, and both indexOf and contains share same signature.

arr.has could be fine, if we also rename str.contains to str.has.

# Domenic Denicola (10 years ago)

If that's the argument, then Array.prototype.contains should accept another Array, not an element to check.

# Mariusz Nowak (10 years ago)

...and same for indexOf and lastIndexOf? ;-)

# Boris Zbarsky (10 years ago)

On 3/6/14 6:45 PM, C. Scott Ananian wrote:

And don't forget the related DOMTokenList, which is in Element.classList and thus used by everyone always.

How is it related? DOMTokenList is indeed an API for a list of strings (sort of; they're pretty restricted in terms of what strings they can be), but has a bunch of other functionality that DOMStringList does not have and that ES arrays don't have and shouldn't have. toggle() doesn't make sense on arrays in general, for example.

The contains and item methods are in DOMTokenList, so they probably shouldn't be removed from DOMStringList.

I think I missed a logical connection here. Can you expand on the reasoning here?

But I don't think anyone was seriously proposing that

I am seriously proposing that DOMStringList go away compeletely and APIs that return it just return Arrays. Not subclasses of Arrays, just Arrays.

(and maybe DOMTokenList would also be related to Array?)

DOMTokenList is writable and the writes must enforce all sorts of invariants that Arrays do not enforce, so making it a subclass of Array would be slightly odd, actually. The main benefit would be to get map() and company working on it, which may be worth it.

# Boris Zbarsky (10 years ago)

On 3/6/14 6:15 PM, Joshua Bell wrote:

FWIW, Blink uses DOMStringList only in IndexedDB and apparently in Location.ancestorOrigins

Indeed. And Location.ancestorOrigins is fairly new and not broadly implemented, so I don't expect its behavior to be a strong compat constraint.

So I guess that leaves us with a few questions:

  1. Is it still early enough in the indexeddb world that we can change the thing it uses from DOMStringList to Array. And if so whether that's a change we want to make.

  2. If we want to keep the non-writing behavior for indexeddb or for some other reason (insufficiently flexible bindings systems?) can't switch ti to Array for now, can we just remove item() and contains() from DOMStringList to make the switch easier later?

# Maël Nison (10 years ago)

Isn't replacing DOMStringList a different issue than adding Array.prototype.contains ?

Using indexOf is possible, but a .contains() method would give a stronger notice of intent when reading code.

# Will Ray (10 years ago)

Additionally, .contains() can be used in a conditional statement directly, while .indexOf() requires the result of a comparison with -1 (or a bitwise inversion, which is not terribly intuitive). It's just more room for simple typos.

Will Ray

# Rick Waldron (10 years ago)

Array.prototype.contains has been approved for the ES7 process: rwaldron/tc39-notes/blob/master/es6/2014-04/apr-9.md#45

# Domenic Denicola (10 years ago)

Yes. Everyone agrees .contains is good. It will happen.

There was some debate about .has vs. .contains, but from what I recall I was one of the only people pushing for .has, and I have since changed my mind.

I am hopeful in fact that .contains is so simple and uncontroversial that we can push it through the post-ES6 spec process very quickly, including into implementations.

# Garrett Smith (10 years ago)

On 7/23/14, Maël Nison <nison.mael at gmail.com> wrote:

Isn't replacing DOMStringList a different issue than adding Array.prototype.contains ?

Using indexOf is possible, but a .contains() method would give a stronger notice of intent when reading code.

So too, for cases of removing an item, would Array.prototype.remove(v) show clear intent.

# Alex Vincent (10 years ago)

On Wed, Jul 23, 2014 at 11:18 AM, <es-discuss-request at mozilla.org> wrote:

So too, for cases of removing an item, would Array.prototype.remove(v) show clear intent.

I would actually raise a concern about that method. Suppose v shows up in the array more than once. Do you remove the first appearance, the last, or all of them?

# Michael Haufe (10 years ago)

Array.prototype.removeAt(index); Array.prototype.remove(element);

# Alex Vincent (10 years ago)

On Wed, Jul 23, 2014 at 2:00 PM, Michael Haufe <tno at thenewobjective.com>

wrote:

Array.prototype.removeAt(index); Array.prototype.remove(element);

We already have an equivalent of removeAt: Array.prototype.splice(index, 1). My concern about remove still stands.

# Andrea Giammarchi (10 years ago)

agreed, already imagining loops like

while (arr.contains(value)) arr.remove(value);

although that looks a bit nicer than

var i;
while (-1 < (i = arr.indexOf(value))) arr.splice(i, 1);

my main concern about .contains() is its potentially un-optimal implementation and error prone logic.

Most of the time we want to know if an array contains something to avoid duplicated because we are missing .unique()

if (!arr.contains(obj)) arr.push(obj);

Most other times we want to do some action with that contained value or its index and here we have a redundant and error prone cases:

if (arr.contains(obj)) {
  // need the index anyway
  var i = arr.indexOf(obj); // but this might fail !!!!
  // splice or do other things ...
}

AFAIR the latter .contains() does not suffer same problems .indexOf() does and this will result in incompatible operations with array indexes, assuming contains told us we are good to go.

As example, .contains(NaN) can cause disaster-prone logics if followed by .indexOf(NaN) because the first check will tell the developer at runtime for sure something was there while the second check will return a lovely -1 most likely unexpected inside the block that believe .contains(value) was a safe bet.

Just my 2 cents on an issue I see coming soon on your screens

# Garrett Smith (10 years ago)

On 7/23/14, Andrea Giammarchi <andrea.giammarchi at gmail.com> wrote:

agreed, already imagining loops like

while (arr.contains(value)) arr.remove(value);

although that looks a bit nicer than

var i;
while (-1 < (i = arr.indexOf(value))) arr.splice(i, 1);

my main concern about .contains() is its potentially un-optimal implementation and error prone logic.

Most of the time we want to know if an array contains something to avoid duplicated because we are missing .unique()

if (!arr.contains(obj)) arr.push(obj);

Most other times we want to do some action with that contained value or its index and here we have a redundant and error prone cases:

if (arr.contains(obj)) {
  // need the index anyway
  var i = arr.indexOf(obj); // but this might fail !!!!
  // splice or do other things ...
}

AFAIR the latter .contains() does not suffer same problems .indexOf() does and this will result in incompatible operations with array indexes, assuming contains told us we are good to go.

As example, .contains(NaN) can cause disaster-prone logics if followed by .indexOf(NaN) because the first check will tell the developer at runtime for sure something was there while the second check will return a lovely -1 most likely unexpected inside the block that believe .contains(value) was a safe bet.

// Contains NaN: [1, NaN, ].some(function(e) {return Number.isNaN(e);})

# Will Ray (10 years ago)

Would Array.prototype.removeAll(element); be worth considering? In the same vein as querySelector/querySelectorAll?

# Andrea Giammarchi (10 years ago)

What is this about? Not an answer nor a solution to what I've said... Just think that NaN is rarely an explicit value, rather something potentially generated at runtime. Would you .some(Number.isNAN.bind(Number)) all the Arrays? I don't think so, at least I wouldn't

Sent from my Windows Phone From: Garrett Smith Sent: ‎7/‎23/‎2014 22:31 To: Andrea Giammarchi Cc: Alex Vincent; es-discuss at mozilla.org Subject: Re: Array.prototype.contains On 7/23/14, Andrea Giammarchi <andrea.giammarchi at gmail.com> wrote:

agreed, already imagining loops like

while (arr.contains(value)) arr.remove(value);

although that looks a bit nicer than

var i;
while (-1 < (i = arr.indexOf(value))) arr.splice(i, 1);

my main concern about .contains() is its potentially un-optimal implementation and error prone logic.

Most of the time we want to know if an array contains something to avoid duplicated because we are missing .unique()

if (!arr.contains(obj)) arr.push(obj);

Most other times we want to do some action with that contained value or its index and here we have a redundant and error prone cases:

if (arr.contains(obj)) {
  // need the index anyway
  var i = arr.indexOf(obj); // but this might fail !!!!
  // splice or do other things ...
}

AFAIR the latter .contains() does not suffer same problems .indexOf() does and this will result in incompatible operations with array indexes, assuming contains told us we are good to go.

As example, .contains(NaN) can cause disaster-prone logics if followed by .indexOf(NaN) because the first check will tell the developer at runtime for sure something was there while the second check will return a lovely -1 most likely unexpected inside the block that believe .contains(value) was a safe bet.

// Contains NaN: [1, NaN, ].some(function(e) {return Number.isNaN(e);})

# Garrett Smith (10 years ago)

On 7/24/14, Andrea Giammarchi <andrea.giammarchi at gmail.com> wrote:

What is this about? Not an answer nor a solution to what I've said... Just think that NaN is rarely an explicit value, rather something potentially generated at runtime. Would you .some(Number.isNAN.bind(Number)) all the Arrays? I don't think so, at least I wouldn't

It looked like you were trying to determine if a finite number is in an array. Is that right? That answer to how to do that would be:

Number.isFinite(v) && arr.indexOf(v) != -1;

# Andrea Giammarchi (10 years ago)

no, my concern is about having different results between .contains() and .indexOf() in production code ... the NaN was the most obvious case/example on how that could go deadly wrong.

if a.contains(v) i = a.indexOf(v); now enjoy inconsistency with what you were expecting ^_^

Just to clarify, I am not saying .contains() should not exist in first place, I am saying we should fix bloody indexOf too ... we can easily fix broken old gotchas and polyfill them on top instead of mixing up methods used for potentially similar intent but absolutely not replaceable for the same ... if tomorrow everyone will swap from -1 < a.indexOf() to a.contains() maybe that's desired but surely not the same thing, and vice versa when the contained index is needed.

Best