Suggestions for Set
On Mon, Oct 1, 2012 at 8:40 PM, Nicholas C. Zakas < standards at nczconsulting.com> wrote:
I've been playing around with the Set prototypes in Firefox and Chrome (knowing full well that they are incomplete and the spec hasn't been finalized yet), and I wanted to share a couple of learnings.
First, since a Set can be initialized with an array, it stands to reason that you should be able to easily get an array back from the set. However, there is no way to do that right now short of using a loop and manually constructing an array. I would really like to see a *Set.prototype.toArray
- method to easily change the Set back into an array. A simple use case would be de-duping an array:
function dedupe(array) { return (new Set(array)).toArray(); }
In July, Array.from was upgraded to also accept objects with iterators (in addition to Array-likes). Set is an iterator, so it could be used to construct a new array:
function dedupe(array) { return Array.from(new Set(array)); }
Rick Waldron wrote:
On Mon, Oct 1, 2012 at 8:40 PM, Nicholas C. Zakas <standards at nczconsulting.com <mailto:standards at nczconsulting.com>> wrote:
I've been playing around with the Set prototypes in Firefox and Chrome (knowing full well that they are incomplete and the spec hasn't been finalized yet), and I wanted to share a couple of learnings. First, since a Set can be initialized with an array, it stands to reason that you should be able to easily get an array back from the set. However, there is no way to do that right now short of using a loop and manually constructing an array. I would really like to see a *Set.prototype.toArray* method to easily change the Set back into an array. A simple use case would be de-duping an array: function dedupe(array) { return (new Set(array)).toArray(); }
In July, Array.from was upgraded to also accept objects with iterators (in addition to Array-likes). Set is an iterator
Nit: "Set is an iterable" or "Set has an iterator".
Nicholas C. Zakas wrote:
I've been playing around with the Set prototypes in Firefox and Chrome (knowing full well that they are incomplete and the spec hasn't been finalized yet), and I wanted to share a couple of learnings.
Thanks!
First, since a Set can be initialized with an array, it stands to reason that you should be able to easily get an array back from the set. However, there is no way to do that right now short of using a loop and manually constructing an array. I would really like to see a Set.prototype.toArray method to easily change the Set back into an array. A simple use case would be de-duping an array:
function dedupe(array) { return (new Set(array)).toArray(); }
Array.from is the way we hope to avoid burdening many iterables with "toArray" methods, as Rick pointed out. Ok?
Second, the lack of visibility into Sets is problematic. A very simple use case is when I want to see if the Set has been initialized yet but I can't know what keys might have been used at that point in time. Firefox implements a Set.prototype.size method which is useful to know what I'm dealing with. However, I'm not sure how frequently the number of items in the Set actually matters, so a Set.prototype.isEmpty would be equally useful for this case.
+1 on isEmpty().
Otherwise, I'm finding Sets very useful as a replacement for objects that I was using for the same purpose.
Cool. Have you tried Maps for those cases where you want value -> value
mappings?
-----Original Message----- From: es-discuss-bounces at mozilla.org [mailto:es-discuss-bounces at mozilla.org] On Behalf Of Brendan Eich Sent: Monday, October 1, 2012 21:43 To: Nicholas C. Zakas
I would really like to see a Set.prototype.toArray method to easily change the Set back into an array. A simple use case would be de-duping an array:
function dedupe(array) { return (new Set(array)).toArray(); }
Array.from is the way we hope to avoid burdening many iterables with "toArray" methods, as Rick pointed out. Ok?
Also:
function dedupe(array) { return [...new Set(array)]; }
This works in Firefox Aurora, for the record :)
On 10/1/2012 6:43 PM, Brendan Eich wrote:
Nicholas C. Zakas wrote:
I've been playing around with the Set prototypes in Firefox and Chrome (knowing full well that they are incomplete and the spec hasn't been finalized yet), and I wanted to share a couple of learnings.
Thanks!
First, since a Set can be initialized with an array, it stands to reason that you should be able to easily get an array back from the set. However, there is no way to do that right now short of using a loop and manually constructing an array. I would really like to see a Set.prototype.toArray method to easily change the Set back into an array. A simple use case would be de-duping an array:
function dedupe(array) { return (new Set(array)).toArray(); }
Array.from is the way we hope to avoid burdening many iterables with "toArray" methods, as Rick pointed out. Ok?
Better than okay, that's great. Having one way to convert iterables to an array makes a lot of sense to me.
Second, the lack of visibility into Sets is problematic. A very simple use case is when I want to see if the Set has been initialized yet but I can't know what keys might have been used at that point in time. Firefox implements a Set.prototype.size method which is useful to know what I'm dealing with. However, I'm not sure how frequently the number of items in the Set actually matters, so a Set.prototype.isEmpty would be equally useful for this case.
+1 on isEmpty().
:D
Otherwise, I'm finding Sets very useful as a replacement for objects that I was using for the same purpose.
Cool. Have you tried Maps for those cases where you want value -> value mappings?
Not yet, that's next on my list.
On Mon, Oct 1, 2012 at 11:46 PM, Domenic Denicola <domenic at domenicdenicola.com> wrote:
-----Original Message----- From: es-discuss-bounces at mozilla.org [mailto:es-discuss-bounces at mozilla.org] On Behalf Of Brendan Eich Sent: Monday, October 1, 2012 21:43 To: Nicholas C. Zakas
I would really like to see a Set.prototype.toArray method to easily change the Set back into an array. A simple use case would be de-duping an array:
function dedupe(array) { return (new Set(array)).toArray(); }
Array.from is the way we hope to avoid burdening many iterables with "toArray" methods, as Rick pointed out. Ok?
Also:
function dedupe(array) { return [...new Set(array)]; }
I'm not sure we ended up with iteration for spread?
Another alternative:
function dedupe(array) { return [x for x of new Set(array)]; }
On Tue, Oct 2, 2012 at 4:26 PM, Erik Arvidsson <erik.arvidsson at gmail.com>wrote:
On Mon, Oct 1, 2012 at 11:46 PM, Domenic Denicola <domenic at domenicdenicola.com> wrote:
-----Original Message----- From: es-discuss-bounces at mozilla.org [mailto: es-discuss-bounces at mozilla.org] On Behalf Of Brendan Eich Sent: Monday, October 1, 2012 21:43 To: Nicholas C. Zakas
I would really like to see a Set.prototype.toArray method to easily change the Set back into an array. A simple use case would be de-duping an array:
function dedupe(array) { return (new Set(array)).toArray(); }
Array.from is the way we hope to avoid burdening many iterables with "toArray" methods, as Rick pointed out. Ok?
Also:
function dedupe(array) { return [...new Set(array)]; }
I'm not sure we ended up with iteration for spread?
Another alternative:
function dedupe(array) { return [x for x of new Set(array)]; }
No iteration for spread, per July 24 resolution esdiscuss/2012-July/024207
From: Rick Waldron [waldron.rick at gmail.com] Sent: Tuesday, October 02, 2012 16:52
No iteration for spread, per July 24 resolution esdiscuss/2012-July/024207
Oh, thanks for catching me on that. Silly Firefox...
This seems like an unfortunate decision, and I couldn't discern the motivation in the minutes. When would I want to use a syntax that fails for iterables? Does [...x] throw for an iterable, or result in something else?
On Tue, Oct 2, 2012 at 5:11 PM, Domenic Denicola < domenic at domenicdenicola.com> wrote:
From: Rick Waldron [waldron.rick at gmail.com] Sent: Tuesday, October 02, 2012 16:52
No iteration for spread, per July 24 resolution esdiscuss/2012-July/024207
Oh, thanks for catching me on that. Silly Firefox...
This seems like an unfortunate decision, and I couldn't discern the motivation in the minutes. When would I want to use a syntax that fails for iterables? Does [...x] throw for an iterable, or result in something else?
The direct reasoning for the resolution was:
"Cannot be both iterable and array-like"
It's possible that this could be added to the agenda for november, if Brendan wants to discuss SpiderMonkey's experience implementing it. It seems to me that if they're not having issues then it's at least worth a mention.
On Tue, Oct 2, 2012 at 2:18 PM, Rick Waldron <waldron.rick at gmail.com> wrote:
On Tue, Oct 2, 2012 at 5:11 PM, Domenic Denicola < domenic at domenicdenicola.com> wrote:
From: Rick Waldron [waldron.rick at gmail.com] Sent: Tuesday, October 02, 2012 16:52
No iteration for spread, per July 24 resolution esdiscuss/2012-July/024207
Oh, thanks for catching me on that. Silly Firefox...
This seems like an unfortunate decision, and I couldn't discern the motivation in the minutes. When would I want to use a syntax that fails for iterables? Does [...x] throw for an iterable, or result in something else?
The direct reasoning for the resolution was:
"Cannot be both iterable and array-like"
It's possible that this could be added to the agenda for november, if Brendan wants to discuss SpiderMonkey's experience implementing it. It seems to me that if they're not having issues then it's at least worth a mention.
Please do. I'd really like to see a more pleasant resolution if one can be found. What does SpiderMonkey actually do?
From: Rick Waldron [mailto:waldron.rick at gmail.com] Sent: Tuesday, October 2, 2012 17:18
On Tue, Oct 2, 2012 at 5:11 PM, Domenic Denicola <domenic at domenicdenicola.com> wrote:
From: Rick Waldron [waldron.rick at gmail.com] Sent: Tuesday, October 02, 2012 16:52
No iteration for spread, per July 24 resolution esdiscuss/2012-July/024207 Oh, thanks for catching me on that. Silly Firefox...
This seems like an unfortunate decision, and I couldn't discern the motivation in the minutes. When would I want to use a syntax that fails for iterables? Does [...x] throw for an iterable, or result in something else?
The direct reasoning for the resolution was:
"Cannot be both iterable and array-like"
I can't really understand what this is trying to say. It must be because I don't understand "iterable". Doesn't it just mean "responds to for-of"? I would imagine arrays, NodeLists, arguments, and other array-likes all respond to for-of; if they don't, that seriously decreases the utility of for-of!
It's possible that this could be added to the agenda for november, if Brendan wants to discuss SpiderMonkey's experience implementing it. It seems to me that if they're not having issues then it's at least worth a mention.
Yay!
On Oct 2, 2012, at 2:43 PM, Mark S. Miller wrote:
On Tue, Oct 2, 2012 at 2:18 PM, Rick Waldron <waldron.rick at gmail.com> wrote:
The direct reasoning for the resolution was:
"Cannot be both iterable and array-like"
It's possible that this could be added to the agenda for november, if Brendan wants to discuss SpiderMonkey's experience implementing it. It seems to me that if they're not having issues then it's at least worth a mention.
Please do. I'd really like to see a more pleasant resolution if one can be found. What does SpiderMonkey actually do?
This thread from July is relevant esdiscuss/2012-July/023918
In particular
On Jul 5, 2012, at 10:54 AM, Brendan Eich wrote:
Allen privately observed that Array forEach skips holes, matching for-in. That counts for a lot with me -- we have only a blind for(i=0;i<a.length;i++)... loop not skipping holes, but of course it wouldn't. That is weak precedent on which to build for-of.
Specifically, for consistency, I think
array.forEach((v)=>console.log(v));
and
for (let v of array) console.log(v);
should yield the same results.
[].forEach skips "holes" so the default iterator for arrays should too. All the other "Array extras" also have the skipping behavior.
Map may win at some point, who knows? It's not winning if one wants an array, numeric indexing, .length, the usual prototype methods.
We could consider also have "dense" interators available:
for (let v of array.denseValues) console.log(v);
Allen
Hopefully we don't have to re-discuss too much of this.
Domenic Denicola wrote:
From: Rick Waldron [mailto:waldron.rick at gmail.com]
This seems like an unfortunate decision, and I couldn't discern the motivation in the minutes. When would I want to use a syntax that fails for iterables? Does [...x] throw for an iterable, or result in something else?
The direct reasoning for the resolution was:
"Cannot be both iterable and array-like"
I can't really understand what this is trying to say. It must be because I don't understand "iterable". Doesn't it just mean "responds to for-of"?
It means (in ES6, SpiderMonkey uses a string property name 'iterator') that the object in question ("is obj iterable?) has an @iterator property, which when called gets or creates an iterator for obj.
I would imagine arrays, NodeLists, arguments, and other array-likes all respond to for-of; if they don't, that seriously decreases the utility of for-of!
Array.from is that an object is either iterable, or failing that, array-like (even if no .length property, ToUint32(undefined) => 0 so no
elements). See bottom of esdiscuss/2012-July/024207.
As Allen's followup points out, array iteration skips holes, to match Array.prototype.forEach. Should spread fill holes or skip them?
It's possible that this could be added to the agenda for november, if Brendan wants to discuss SpiderMonkey's experience implementing it. It seems to me that if they're not having issues then it's at least worth a mention.
Yay!
I actually do not remember why we went back to only array-like instead of iterable || array-like for spread. Can someone (Rick? Dave? Arv?) recall?
Brendan Eich wrote:
I would imagine arrays, NodeLists, arguments, and other array-likes all respond to for-of; if they don't, that seriously decreases the utility of for-of!
Array.from is
s/is/tests/
that an object is either iterable, or failing that, array-like (even if no .length property, ToUint32(undefined) => 0 so no elements). See bottom of esdiscuss/2012-July/024207.
As for the list of built-ins after arrays, specifically "NodeLists, arguments, ..." I agree these should all be iterable.
On Oct 2, 2012, at 3:55 PM, Brendan Eich wrote:
Domenic Denicola wrote:
From: Rick Waldron [mailto:waldron.rick at gmail.com]
This seems like an unfortunate decision, and I couldn't discern the motivation in the minutes. When would I want to use a syntax that fails for iterables? Does [...x] throw for an iterable, or result in something else?
The direct reasoning for the resolution was:
"Cannot be both iterable and array-like"
I can't really understand what this is trying to say. It must be because I don't understand "iterable". Doesn't it just mean "responds to for-of"?
It means (in ES6, SpiderMonkey uses a string property name 'iterator') that the object in question ("is obj iterable?) has an @iterator property, which when called gets or creates an iterator for obj.
I would imagine arrays, NodeLists, arguments, and other array-likes all respond to for-of; if they don't, that seriously decreases the utility of for-of!
Array.from is that an object is either iterable, or failing that, array-like (even if no .length property, ToUint32(undefined) => 0 so no elements). See bottom of esdiscuss/2012-July/024207.
But also see ecmascript#588 and in particular comment 1 which says:
Did we talk about the implications of of using iterable protocol if the array has holes?
The proposed standard iterator for Arrays turns holes into undefined. While normal array-like iteration skips holes. I would expect that
let a2 = Array.from([,,,,5]);
would produce a new array that was just like the argument array. But using iterator protocol would make it just like:
let a3 = Array.from([undefined, undefined, undefined, undefined, 5]);
It seems to me that the right solution, is that if the from argument is a real Array then Array-like, hole preservation, iteration should be used. If it isn't a real Array, then from should first try iterable protocol and if it isn't there fall back to array-like.
As Allen's followup points out, array iteration skips holes, to match Array.prototype.forEach. Should spread fill holes or skip them?
Holes need to be skipped if we expect
var arrayWithHoles = [,,2,,,5]; var copyOfArrayWithHoles = [...arrayWithHoles]];
to make an accurate copy.
Allen Wirfs-Brock wrote:
Did we talk about the implications of of using iterable protocol if the array
has holes?
We did, and some of us agreed that a.forEach skips holes, so for (v of a) should too.
But you are right, that means spread can't sensibly use iteration.
On the other hand, drafted and prototyped iteration on arrays does not currently skip holes. It fills them in argument list and enclosing array literals. In the latter it could preserve holes rather than filling them with undefined values, but in argument lists there's no such thing as a hole.
Which is more important, iterating over holes (preserved if possible), or skipping them and therefore spreading array-likes but not iterables?
On 3 October 2012 05:38, Brendan Eich <brendan at mozilla.com> wrote:
Which is more important, iterating over holes (preserved if possible), or skipping them and therefore spreading array-likes but not iterables?
I, for one, couldn't care less about holes. We shouldn't compromise any useful feature just for the sake of preserving some array hole craziness.
On Wed, Oct 3, 2012 at 10:24 AM, Andreas Rossberg <rossberg at google.com>wrote:
On 3 October 2012 05:38, Brendan Eich <brendan at mozilla.com> wrote:
Which is more important, iterating over holes (preserved if possible), or skipping them and therefore spreading array-likes but not iterables?
I, for one, couldn't care less about holes. We shouldn't compromise any useful feature just for the sake of preserving some array hole craziness.
I agree. Unless there's a sane use case for holes with the spread operator, I don't think it makes sense to make compromises because of them, especially since we aren't breaking backwards compatibility or anything. We can actually make something better here.
On Wed, Oct 3, 2012 at 3:47 AM, Jussi Kalliokoski < jussi.kalliokoski at gmail.com> wrote:
On Wed, Oct 3, 2012 at 10:24 AM, Andreas Rossberg <rossberg at google.com>wrote:
On 3 October 2012 05:38, Brendan Eich <brendan at mozilla.com> wrote:
Which is more important, iterating over holes (preserved if possible), or skipping them and therefore spreading array-likes but not iterables?
I, for one, couldn't care less about holes. We shouldn't compromise any useful feature just for the sake of preserving some array hole craziness.
I agree. Unless there's a sane use case for holes with the spread operator, I don't think it makes sense to make compromises because of them, especially since we aren't breaking backwards compatibility or anything. We can actually make something better here.
I seem to remember an issue re: what to do with infinite iterators (generators)? If that's correct, was there an agreed-upon resolution?
Dean Landolt wrote:
On Wed, Oct 3, 2012 at 3:47 AM, Jussi Kalliokoski <jussi.kalliokoski at gmail.com <mailto:jussi.kalliokoski at gmail.com>> wrote:
On Wed, Oct 3, 2012 at 10:24 AM, Andreas Rossberg <rossberg at google.com <mailto:rossberg at google.com>> wrote: On 3 October 2012 05:38, Brendan Eich <brendan at mozilla.com <mailto:brendan at mozilla.com>> wrote: > Which is more important, iterating over holes (preserved if possible), or > skipping them and therefore spreading array-likes but not iterables? I, for one, couldn't care less about holes. We shouldn't compromise any useful feature just for the sake of preserving some array hole craziness. I agree. Unless there's a sane use case for holes with the spread operator, I don't think it makes sense to make compromises because of them, especially since we aren't breaking backwards compatibility or anything. We can actually make something better here.
I seem to remember an issue re: what to do with infinite iterators (generators)? If that's correct, was there an agreed-upon resolution?
Does it need one? I mean, the process crashes on out-of-memory error. Or is it some different issue here?
On Wed, Oct 3, 2012 at 3:24 AM, Andreas Rossberg <rossberg at google.com> wrote:
On 3 October 2012 05:38, Brendan Eich <brendan at mozilla.com> wrote:
Which is more important, iterating over holes (preserved if possible), or skipping them and therefore spreading array-likes but not iterables?
I, for one, couldn't care less about holes. We shouldn't compromise any useful feature just for the sake of preserving some array hole craziness.
Filling in holes with undefined seems like the right thing to do. People do not depend on holes.
Having Array.prototype. at iterator skip holes is bad because we don't have the index so we don't know that anything was skipped.
To repeat myself; holes are not common and we should keep things simple and having Array.prototype. at iterator iterate over array[0] to array[length - 1] is the most expected result.
On Wed, Oct 3, 2012 at 10:47 AM, Erik Arvidsson <erik.arvidsson at gmail.com>wrote:
On Wed, Oct 3, 2012 at 3:24 AM, Andreas Rossberg <rossberg at google.com> wrote:
On 3 October 2012 05:38, Brendan Eich <brendan at mozilla.com> wrote:
Which is more important, iterating over holes (preserved if possible), or
skipping them and therefore spreading array-likes but not iterables?
I, for one, couldn't care less about holes. We shouldn't compromise any useful feature just for the sake of preserving some array hole craziness.
Filling in holes with undefined seems like the right thing to do. People do not depend on holes.
Having Array.prototype. at iterator skip holes is bad because we don't have the index so we don't know that anything was skipped.
To repeat myself; holes are not common and we should keep things simple and having Array.prototype. at iterator iterate over array[0] to array[length - 1] is the most expected result.
+1
In the "trenches", most devs consider holes to be a myth. Most have never seen or had experience with code that relies on holes or even suffers when holes exist. There are many sources that will back this claim, but at the moment I can't invest the time to look up and compile a list (if i have time later)
Rick Waldron wrote:
On Wed, Oct 3, 2012 at 10:47 AM, Erik Arvidsson <erik.arvidsson at gmail.com <mailto:erik.arvidsson at gmail.com>> wrote:
On Wed, Oct 3, 2012 at 3:24 AM, Andreas Rossberg <rossberg at google.com <mailto:rossberg at google.com>> wrote: > On 3 October 2012 05:38, Brendan Eich <brendan at mozilla.com <mailto:brendan at mozilla.com>> wrote: >> Which is more important, iterating over holes (preserved if possible), or >> skipping them and therefore spreading array-likes but not iterables? > > I, for one, couldn't care less about holes. We shouldn't compromise > any useful feature just for the sake of preserving some array hole > craziness. Filling in holes with undefined seems like the right thing to do. People do not depend on holes. Having Array.prototype. at iterator skip holes is bad because we don't have the index so we don't know that anything was skipped. To repeat myself; holes are not common and we should keep things simple and having Array.prototype. at iterator iterate over array[0] to array[length - 1] is the most expected result.
+1
In the "trenches", most devs consider holes to be a myth. Most have never seen or had experience with code that relies on holes or even suffers when holes exist. There are many sources that will back this claim, but at the moment I can't invest the time to look up and compile a list (if i have time later)
Ok, I buy it.
In that case, why shouldn't spread match Array.from and use iterable-else-array-like?
Holes:
www.youtube.com/watch?v=bFNx7YFwFfI, www.youtube.com/watch?v=dI
Dean Landolt wrote:
On Wed, Oct 3, 2012 at 3:47 AM, Jussi Kalliokoski <jussi.kalliokoski at gmail.com <mailto:jussi.kalliokoski at gmail.com>> wrote:
On Wed, Oct 3, 2012 at 10:24 AM, Andreas Rossberg <rossberg at google.com <mailto:rossberg at google.com>> wrote: On 3 October 2012 05:38, Brendan Eich <brendan at mozilla.com <mailto:brendan at mozilla.com>> wrote: > Which is more important, iterating over holes (preserved if possible), or > skipping them and therefore spreading array-likes but not iterables? I, for one, couldn't care less about holes. We shouldn't compromise any useful feature just for the sake of preserving some array hole craziness. I agree. Unless there's a sane use case for holes with the spread operator, I don't think it makes sense to make compromises because of them, especially since we aren't breaking backwards compatibility or anything. We can actually make something better here.
I seem to remember an issue re: what to do with infinite iterators (generators)? If that's correct, was there an agreed-upon resolution?
This is just a D.o.S. hazard that engines must defend against with memory and time-based watchdogs. Even if spread considered only array-like types and not iterables first, a huge array or lying proxy could DoS it. Separate concern, dealt with generically.
On Wed, Oct 3, 2012 at 9:47 AM, Erik Arvidsson <erik.arvidsson at gmail.com> wrote:
On Wed, Oct 3, 2012 at 3:24 AM, Andreas Rossberg <rossberg at google.com> wrote:
On 3 October 2012 05:38, Brendan Eich <brendan at mozilla.com> wrote:
Which is more important, iterating over holes (preserved if possible), or skipping them and therefore spreading array-likes but not iterables?
I, for one, couldn't care less about holes. We shouldn't compromise any useful feature just for the sake of preserving some array hole craziness.
Filling in holes with undefined seems like the right thing to do. People do not depend on holes.
Having Array.prototype. at iterator skip holes is bad because we don't have the index so we don't know that anything was skipped.
I agree. Firefox currently fills holes in with undefined: js> var a = [1,,,,2]; js> [...a] [1, undefined, undefined, undefined, 2]
Of course we'll eventually implement whatever TC39 specifies, and I don't think it matters too much; but I like this behavior because
-
the spread syntax just uses the iteration protocol;
-
it lets developers continue to ignore any holes they might have in their arrays (that is, it doesn't "squeeze out" the holes, which those developers might find astonishing--of course if they use .sort() or .forEach() on that array, they'll be astonished anyway).
A couple observations:
-
this whole issue is only relevant if you actually have array objects containing holes. Special treat for sparse arrays doesn't hurt anybody (other than implementors) who doesn't use them.
-
If we (and the broader developer community) don't like sparse behavior for Array then rather than introducing additional inconsistencies about the handling of hole (for example, making Array.forEach and for-of on a sparse array different) it would be better to simply see if we can eliminate (or compartmentalize) the sparse behavior of arrays.
Some possible approaches
-
Make all array instances dense and see what really breaks. Possibly provide a new SparseArray "subclass". Anyone brave enough to do the experiment?
-
Formalize the concept of sparseness into either a selectable attribute of arrays or as a special "subclass" of array. Most current obviously non-sparse usages get the dense version:
var aDenseArray = [0,1,2,3,4,5,6,7]; var aSparseArray = [,,,,,,7];
console.log.(aDenseArray.isSparse()); //false console.log.(aSparseArray.isSparse()); //true
var dense2 = new Array(0,1,2,3,4,5);
var dense3 = new Array(1000); console.log.(dense3.isSparse()); //false
var sparse2 = new Array(1001); console.log.(dense3.isSparse()); //true
var sparse3 = Array.sparse(); console.log.(sparse3.isSparse()); //true
On Oct 3, 2012, at 7:47 AM, Erik Arvidsson wrote:
On Wed, Oct 3, 2012 at 3:24 AM, Andreas Rossberg <rossberg at google.com> wrote:
On 3 October 2012 05:38, Brendan Eich <brendan at mozilla.com> wrote:
Which is more important, iterating over holes (preserved if possible), or skipping them and therefore spreading array-likes but not iterables?
I, for one, couldn't care less about holes. We shouldn't compromise any useful feature just for the sake of preserving some array hole craziness.
Filling in holes with undefined seems like the right thing to do. People do not depend on holes.
Having Array.prototype. at iterator skip holes is bad because we don't have the index so we don't know that anything was skipped.
To repeat myself; holes are not common and we should keep things simple and having Array.prototype. at iterator iterate over array[0] to array[length - 1] is the most expected result.
However, that would mean that Array.prototype.forEach and for-of over the same array are not always interchangeable.
Allen Wirfs-Brock wrote:
On Oct 3, 2012, at 7:47 AM, Erik Arvidsson wrote:
On Wed, Oct 3, 2012 at 3:24 AM, Andreas Rossberg<rossberg at google.com> wrote:
On 3 October 2012 05:38, Brendan Eich<brendan at mozilla.com> wrote:
Which is more important, iterating over holes (preserved if possible), or skipping them and therefore spreading array-likes but not iterables? I, for one, couldn't care less about holes. We shouldn't compromise any useful feature just for the sake of preserving some array hole craziness. Filling in holes with undefined seems like the right thing to do. People do not depend on holes.
Having Array.prototype. at iterator skip holes is bad because we don't have the index so we don't know that anything was skipped.
To repeat myself; holes are not common and we should keep things simple and having Array.prototype. at iterator iterate over array[0] to array[length - 1] is the most expected result.
However, that would mean that Array.prototype.forEach and for-of over the same array are not always interchangeable.
Yes, that's the trade-off.
Holes are considered harmful, almost always a bug, so this is probably tolerable (or even helpful if it flushes out bugs when someone swaps forEach and for-of). Mainly holes are an anti-pattern.
Jason Orendorff wrote:
On Wed, Oct 3, 2012 at 9:47 AM, Erik Arvidsson<erik.arvidsson at gmail.com> wrote:
On Wed, Oct 3, 2012 at 3:24 AM, Andreas Rossberg<rossberg at google.com> wrote:
On 3 October 2012 05:38, Brendan Eich<brendan at mozilla.com> wrote:
Which is more important, iterating over holes (preserved if possible), or skipping them and therefore spreading array-likes but not iterables? I, for one, couldn't care less about holes. We shouldn't compromise any useful feature just for the sake of preserving some array hole craziness. Filling in holes with undefined seems like the right thing to do. People do not depend on holes.
Having Array.prototype. at iterator skip holes is bad because we don't have the index so we don't know that anything was skipped.
I agree. Firefox currently fills holes in with undefined: js> var a = [1,,,,2]; js> [...a] [1, undefined, undefined, undefined, 2]
Of course we'll eventually implement whatever TC39 specifies, and I don't think it matters too much; but I like this behavior because
- the spread syntax just uses the iteration protocol;
This differs from Array.from -- any reason not to fall back on the array-like protocol (which for missing 'length' iterates no values)?
- it lets developers continue to ignore any holes they might have in their arrays (that is, it doesn't "squeeze out" the holes, which those developers might find astonishing--of course if they use .sort() or .forEach() on that array, they'll be astonished anyway).
I agree -- I'm persuaded we should diverge for-of from forEach. This lets us unify spread with Array.from (I hope). Anyone object?
On Wed, Oct 3, 2012 at 11:34 AM, Brendan Eich <brendan at mozilla.com> wrote:
- the spread syntax just uses the iteration protocol;
This differs from Array.from -- any reason not to fall back on the array-like protocol (which for missing 'length' iterates no values)?
I think ES6 should have a single how-to-iterate behavior shared by Array.from, spread syntax, and for-of.
Whether that includes a fallback to .length or not seems less important to me.
It seems simpler not to include the fallback. Firefox doesn't include it at present. Instead, arraylike objects are pretty much all iterable. That wasn't hard to do, since our Array.prototype.iterator is generic.
Jason Orendorff wrote:
On Wed, Oct 3, 2012 at 11:34 AM, Brendan Eich<brendan at mozilla.com> wrote:
- the spread syntax just uses the iteration protocol; This differs from Array.from -- any reason not to fall back on the array-like protocol (which for missing 'length' iterates no values)?
I think ES6 should have a single how-to-iterate behavior shared by Array.from, spread syntax, and for-of.
Whether that includes a fallback to .length or not seems less important to me.
It seems simpler not to include the fallback. Firefox doesn't include it at present. Instead, arraylike objects are pretty much all iterable. That wasn't hard to do, since our Array.prototype.iterator is generic.
I buy it.
Not sure why we didn't do it in the July meeting where we settled on Array.from testing iterable and falling back on array-like. Perhaps fear that @iterator customizations will be missing from a number of array-likes.
On that point, does NodeList have an iterator in Firefox now? That's an obvious Array.from argument type.
On Wed, Oct 3, 2012 at 1:57 PM, Brendan Eich <brendan at mozilla.com> wrote:
On that point, does NodeList have an iterator in Firefox now? That's an obvious Array.from argument type.
Yep!
> document.body.querySelectorAll("p").iterator()
[object Iterator]
> [...document.body.querySelectorAll("p")].length
1
Huh. Only one? That's weird, I thought gmail would have lots of <p> elements.
> [...document.body.querySelectorAll("div")].length
1723
There we go.
On Wed, Oct 3, 2012 at 2:57 PM, Brendan Eich <brendan at mozilla.com> wrote:
Jason Orendorff wrote:
On Wed, Oct 3, 2012 at 11:34 AM, Brendan Eich<brendan at mozilla.com> wrote:
- the spread syntax just uses the iteration protocol;
This differs from Array.from -- any reason not to fall back on the array-like protocol (which for missing 'length' iterates no values)?
I think ES6 should have a single how-to-iterate behavior shared by Array.from, spread syntax, and for-of.
Whether that includes a fallback to .length or not seems less important to me.
It seems simpler not to include the fallback. Firefox doesn't include it at present. Instead, arraylike objects are pretty much all iterable. That wasn't hard to do, since our Array.prototype.iterator is generic.
I buy it.
Not sure why we didn't do it in the July meeting where we settled on Array.from testing iterable and falling back on array-like. Perhaps fear that @iterator customizations will be missing from a number of array-likes.
I didn't realize that existing built-ins and DOM APIs would be modified to implement the iterator protocol.
One of the reasons we decided to make spread, rest and destructuring "array-like" only was to limit the surprise factor that would occur with sparse arrays. The behaviour we wanted to avoid is present in Firefox 18
var a = new Array(10);
// A console.log( a.map(function() { return 1; }) ); // [, , , , , , , , , ,] // B console.log( [...a].map(function() { return 1; }) ); // [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
From the notes:
Destructing and spread - no iterator protocol. (return to existing draft semantics of arraylike — [Cannot be both iterable and array-like])
I believe this was referring to iterator protocol filling in the holes with undefined, creating an unexpected result, therefore something cannot be both iterable and array-like without surprises. The result of calling Array.isArray(a) and Array.isArray([...a]) will be be true, but one appears to be constructed differently then the other.
Changing A to work like B could very well break things; but like Erik, Andreas and I have said above, holes are a myth in real-world code.
At one point I believed I had a valid use case, but it turned out that it was better to manually fill in with undefined.
On Wed, Oct 3, 2012 at 3:47 PM, Jason Orendorff <jason.orendorff at gmail.com>wrote:
On Wed, Oct 3, 2012 at 1:57 PM, Brendan Eich <brendan at mozilla.com> wrote:
On that point, does NodeList have an iterator in Firefox now? That's an obvious Array.from argument type.
Yep!
> document.body.querySelectorAll("p").iterator() [object Iterator] > [...document.body.querySelectorAll("p")].length 1
Huh. Only one? That's weird, I thought gmail would have lots of <p> elements.
> [...document.body.querySelectorAll("div")].length 1723
There we go.
Looks like DOMTokenList as well...
var d = document.createElement("div"); d.className = "foo bar baz"; [...d.classList]
["foo", "bar", "baz"]
:)
This makes a really good case for aligning Array.from, for-of and spread
On Wed, Oct 3, 2012 at 3:53 PM, Rick Waldron <waldron.rick at gmail.com> wrote:
var d = document.createElement("div"); d.className = "foo bar baz"; [...d.classList]
["foo", "bar", "baz"]
targetElement.classList.add(...sourceElement.classList);
:D
But then again that would work even if we didn't use the iteration protocol.
I can't imagine actually getting consensus on making the current default change from sparse to dense. We've rejected many breaking changes that were less breaking than this would be.
The subclass notion is interesting though. Reads dominate writes, and frozen arrays can only be read anyway. Liskov substitutability on reads suggests that dense arrays be a subclass of sparse -- it provides stronger guarantees. Arranging the subclassing that way would also not be a breaking change.
On Wed, Oct 3, 2012 at 4:07 PM, Mark S. Miller <erights at google.com> wrote:
I can't imagine actually getting consensus on making the current default change from sparse to dense. We've rejected many breaking changes that were less breaking than this would be.
The subclass notion is interesting though. Reads dominate writes, and frozen arrays can only be read anyway. Liskov substitutability on reads suggests that dense arrays be a subclass of sparse -- it provides stronger guarantees. Arranging the subclassing that way would also not be a breaking change.
In Sept we briefly discussed an Array subclass "thing" that was never named... IIRC there was some interest, but it was controversial.
I've been playing around with the Set prototypes in Firefox and Chrome (knowing full well that they are incomplete and the spec hasn't been finalized yet), and I wanted to share a couple of learnings.
First, since a Set can be initialized with an array, it stands to reason that you should be able to easily get an array back from the set. However, there is no way to do that right now short of using a loop and manually constructing an array. I would really like to see a Set.prototype.toArray method to easily change the Set back into an array. A simple use case would be de-duping an array:
Second, the lack of visibility into Sets is problematic. A very simple use case is when I want to see if the Set has been initialized yet but I can't know what keys might have been used at that point in time. Firefox implements a Set.prototype.size method which is useful to know what I'm dealing with. However, I'm not sure how frequently the number of items in the Set actually matters, so a Set.prototype.isEmpty would be equally useful for this case.
Otherwise, I'm finding Sets very useful as a replacement for objects that I was using for the same purpose.
Thanks, Nicholas