Array.prototype.contains
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.
except without the property lookup for indexOf.
At this.indexOf
? Or the whole this.indexOf(x) !== -1;
lookup? How else could it work?
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.
That's what I figured - I guess I thinking of implementations that would be ES3 & 5 compat
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.
Sorry I meant Array.prototype.contains
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.
Perhaps using indexOfIdentical from harmony:simple_maps_and_sets
Would it result in DOMStringList actually away?
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.
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.
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
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>
How about obsoleting indexOf, adding something better with a different name, and then building a contains method on top of that?
Peter
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
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 )
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).
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.
Allen, thank you for the clarification there
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?
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.
I'll put up a proposal once electricity is back. I'll use the same comparison as done in maps.
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
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".
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.)
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.
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?
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
+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?
-----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.
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
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.
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?
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.
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.
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
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 ===.
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.
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
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?
Andrea Giammarchi wrote:
I actually agree on this, but Set.has() is misleading then, imho. Shouldn't be specified that
has()
is key related andcontains()
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).
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.
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?
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
+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
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.
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.
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
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?
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.
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.
(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
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.
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
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.
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
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.
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
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.
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).
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
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.
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.
Personally I think the more useful model to follow than String.prototype.contains
is Set.prototype.has
.
Now that you mention it, I completely agree.
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?
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
isSet.prototype.has
.
But then DOM4 DOMStringList
would still have its own contains
and the has
it inherits from Array.prototype
. That seems confusing, no?
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
isSet.prototype.has
.
That would not allow us to kill DOMStringList.
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.
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:
document.styleSheetSets
.- Microdata API.
- Various places in indexeddb.
- The DataTransfer API.
- 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.
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
...
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?
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.
FWIW, Blink uses DOMStringList only in IndexedDB and apparently in Location.ancestorOrigins
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
?)
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.)
Domenic Denicola-2 wrote
Personally I think the more useful model to follow than
String.prototype.contains
isSet.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
.
If that's the argument, then Array.prototype.contains should accept another Array, not an element to check.
...and same for indexOf and lastIndexOf? ;-)
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
anditem
methods are inDOMTokenList
, so they probably shouldn't be removed fromDOMStringList
.
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 toArray
?)
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.
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:
-
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.
-
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?
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.
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
Array.prototype.contains has been approved for the ES7 process: rwaldron/tc39-notes/blob/master/es6/2014-04/apr-9.md#45
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.
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.
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?
Array.prototype.removeAt(index); Array.prototype.remove(element);
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.
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
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);})
Would Array.prototype.removeAll(element); be worth considering? In the same vein as querySelector/querySelectorAll?
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);})
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;
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
harmony:string_extras There is a proposal for String.prototype.contains so why can't I find one for Array.prototype.contains?
.