Re: Re: New Set methods - again

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: Re: New Set methods - again

Peter Jaszkowiak
> Out of curiosity, what is the rationale behind the choices for which non-set-specific, currently-array-only methods to implement?

One rational is that these are also not Array-specific functions either, and serve as much if not more use with sets than with Arrays. I my experience, one of the main reasons that people don't use Set and Map is because they don't have these helpful utility functions.

> For example there is `map`, which saves you one array cast and one set cast, and `find`, which saves you one array cast, but not, e.g., `reduce`, which would also save you one array cast.

`reduce` doesn't make sense for Sets because it is an ordered operation. Sets are unordered, so actually having `forEach` (without the index parameter) makes more sense than `reduce`. 

Having these chainable utility functions on `Set.prototype` will make dealing with Sets much easier for developers, which will increase their usage, making proposals for `Array.prototype.union`, etc less relevant.

In my opinion, a lot more attention should be paid to building and strengthening the standard library of the language instead of adding more and more syntax.


A couple things I'd like to see added / changed with the proposal, though:

- Why can't `Set.prototype.add` be simply extended to accept multiple parameters? This would eliminate the need for `addElements`. If `addElements` is going to be a thing, then it should accept a single Iterable parameter instead.
- IMO, `forEach` should be added if all of these other functional methods are, but it should return `this` as opposed to `Array.prototype.forEach` which returns `undefined`. Alternatively, name it `.each` to signify this slight semantic difference.
- `.flatMap` would be nice to have, flattening Iterables into the new Set, and accepting non-iterables as singular values added to the Set
- I imagine that the concerns over `.union`, `.intersect`, etc being slow when accepting multiple Iterables is avoidable by adding optimizations for single Sets, multiple Sets, and single iterables

As an aside to this proposal, you mentioned an alternative of adding some of these methods to `%IteratorPrototype%`. I think both are good ideas, but the problem is that _really_, only `.map`, `.flatMap`, and `.filter` make sense with generic Iterators if you want to maintain laziness. 


Overall, really good stuff, Michał.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Re: New Set methods - again

Jordan Harband
Set and Map both already have forEach, and both return undefined, just like Array.prototype.forEach.

On Fri, Jul 28, 2017 at 6:57 PM, Peter Jaszkowiak <[hidden email]> wrote:
> Out of curiosity, what is the rationale behind the choices for which non-set-specific, currently-array-only methods to implement?

One rational is that these are also not Array-specific functions either, and serve as much if not more use with sets than with Arrays. I my experience, one of the main reasons that people don't use Set and Map is because they don't have these helpful utility functions.

> For example there is `map`, which saves you one array cast and one set cast, and `find`, which saves you one array cast, but not, e.g., `reduce`, which would also save you one array cast.

`reduce` doesn't make sense for Sets because it is an ordered operation. Sets are unordered, so actually having `forEach` (without the index parameter) makes more sense than `reduce`. 

Having these chainable utility functions on `Set.prototype` will make dealing with Sets much easier for developers, which will increase their usage, making proposals for `Array.prototype.union`, etc less relevant.

In my opinion, a lot more attention should be paid to building and strengthening the standard library of the language instead of adding more and more syntax.


A couple things I'd like to see added / changed with the proposal, though:

- Why can't `Set.prototype.add` be simply extended to accept multiple parameters? This would eliminate the need for `addElements`. If `addElements` is going to be a thing, then it should accept a single Iterable parameter instead.
- IMO, `forEach` should be added if all of these other functional methods are, but it should return `this` as opposed to `Array.prototype.forEach` which returns `undefined`. Alternatively, name it `.each` to signify this slight semantic difference.
- `.flatMap` would be nice to have, flattening Iterables into the new Set, and accepting non-iterables as singular values added to the Set
- I imagine that the concerns over `.union`, `.intersect`, etc being slow when accepting multiple Iterables is avoidable by adding optimizations for single Sets, multiple Sets, and single iterables

As an aside to this proposal, you mentioned an alternative of adding some of these methods to `%IteratorPrototype%`. I think both are good ideas, but the problem is that _really_, only `.map`, `.flatMap`, and `.filter` make sense with generic Iterators if you want to maintain laziness. 


Overall, really good stuff, Michał.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Re: New Set methods - again

Peter Jaszkowiak
Yes I realised that right after sending the reply. Don't know what I was thinking before.

On Jul 29, 2017 00:45, "Jordan Harband" <[hidden email]> wrote:
Set and Map both already have forEach, and both return undefined, just like Array.prototype.forEach.

On Fri, Jul 28, 2017 at 6:57 PM, Peter Jaszkowiak <[hidden email]> wrote:
> Out of curiosity, what is the rationale behind the choices for which non-set-specific, currently-array-only methods to implement?

One rational is that these are also not Array-specific functions either, and serve as much if not more use with sets than with Arrays. I my experience, one of the main reasons that people don't use Set and Map is because they don't have these helpful utility functions.

> For example there is `map`, which saves you one array cast and one set cast, and `find`, which saves you one array cast, but not, e.g., `reduce`, which would also save you one array cast.

`reduce` doesn't make sense for Sets because it is an ordered operation. Sets are unordered, so actually having `forEach` (without the index parameter) makes more sense than `reduce`. 

Having these chainable utility functions on `Set.prototype` will make dealing with Sets much easier for developers, which will increase their usage, making proposals for `Array.prototype.union`, etc less relevant.

In my opinion, a lot more attention should be paid to building and strengthening the standard library of the language instead of adding more and more syntax.


A couple things I'd like to see added / changed with the proposal, though:

- Why can't `Set.prototype.add` be simply extended to accept multiple parameters? This would eliminate the need for `addElements`. If `addElements` is going to be a thing, then it should accept a single Iterable parameter instead.
- IMO, `forEach` should be added if all of these other functional methods are, but it should return `this` as opposed to `Array.prototype.forEach` which returns `undefined`. Alternatively, name it `.each` to signify this slight semantic difference.
- `.flatMap` would be nice to have, flattening Iterables into the new Set, and accepting non-iterables as singular values added to the Set
- I imagine that the concerns over `.union`, `.intersect`, etc being slow when accepting multiple Iterables is avoidable by adding optimizations for single Sets, multiple Sets, and single iterables

As an aside to this proposal, you mentioned an alternative of adding some of these methods to `%IteratorPrototype%`. I think both are good ideas, but the problem is that _really_, only `.map`, `.flatMap`, and `.filter` make sense with generic Iterators if you want to maintain laziness. 


Overall, really good stuff, Michał.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Re: New Set methods - again

Darien Valentine
In reply to this post by Peter Jaszkowiak
> Sets are unordered, so actually having `forEach` (without the index parameter) makes more sense than `reduce`.

When we work with sets, we do often treat them as unordered, like one would in math I suppose, but the ES data structure does have a defined iteration order, and its `forEach` method does call its callback with indices. Set instances are given an internal `[[SetData]]` slot which is [defined as a list](https://tc39.github.io/ecma262/#sec-set-iterable) and ["set iterator"](https://tc39.github.io/ecma262/#sec-set-iterator-objects) uses this and iterates in a deterministic order.

> `reduce` doesn't make sense for Sets because it is an ordered operation.

Ordered-ness of sets in ES aside, there’s nothing inherent to reduction which makes it suitable only with ordered collections; consider the classic reduce example, summing numbers.

Not that I’m advocating for or against the addition of reduce here, that was just an example — just, the choices seemed to me a bit arbitrary. (Generic iterator methods would indeed be a nice, except I’m not sure how it would work since pushing another prototype into the chain between object and array, object and set, object and map etc would be web-breaking.)

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Re: New Set methods - again

Peter Jaszkowiak
In reply to this post by Peter Jaszkowiak
> its `forEach` method does call its callback with indices. 

This is incorrect. Both the `value` and `key` arguments are equal for Sets, equal to the current element in the Set.

From a different reply which I mistakenly forget to CC esdiscuss

> True, Sets are technically ordered by insertion order in their iterator, but they aren't indexed, so certain elements can't be selected like with an Array, and they can't be sorted. `reduce`, in my opinion, still makes little sense given those facts. Especially since the most common use of reduce, in my experience, is to create an object from an array of pairs, this could be handled better by just `new Map(...your_set_of_pairs)`

Reduce seems to make more sense as an ordered operation, but in an attempt to justify adding reduce, here's a use case for an unordered reduce that can't be solved with any other method proposed here, including `.flatMap`. 

```js
const product = numbers.reduce((prev, x) => prev * x, 1);
```

This can't be done without reduce, unless something like `Math.product` gets introduced, which I think it should, but what about multiple exponents? What I want to do a^b^c^d^e^f etc, I'd still need something like reduce for that.

I tried to think of a more complex use case for an index-less `reduce` method, but I couldn't. I thought maybe combinations of elements, but without a way to select a certain subset like `Array#slice`, it's not simple at all. For instance, with an array, you can do the following:

```js
// this works because we have a placeholder `i`
Array.isArray(players) === true;

players.reduce((matches, player, i) => {
  return [...matches, ...players.slice(i + 1).map(vsPlayer => new Match(player, vsPlayer)));
}, []);

// without the index it is not trivial
// it's also much less efficient, probably better to just cast to an Array first
Set.isSet(players) === true;

players.reduce((matches, player, key) => {
  key === player;
  return [...matches, ...players.filter(
  vsPlayer => matches.some(match => !match.players.includes(player) || !match.players.includes(vsPlayer))
  ).map(vsPlayer => new Match(player, vsPlayer))];
}, new Set());
```

The only other orderless operatons that I can think of are things like summing or multiplying numbers, which I do think should be added to the standard library as `Math.sum` and `Math.product`, but it should be possible to do without. So in that case, I guess I agree that `.reduce` should exist on `Set` and `Map`.

I don't see many use cases for `.reduce`, but for consistency, it should be added.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Re: New Set methods - again

Darien Valentine
In reply to this post by Peter Jaszkowiak
>  Both the value and key arguments are equal for Sets

Derp, forgot about that, you’re right. The internal algorithm references the indices, but they aren’t exposed.

> [examples of unordered reduce]

There are quite a few I think — in fact reductions that are order-agnostic are a pretty important concept for parallelism, as seen in the wild in places like MongoDB’s aggregation pipeline. Not super applicable here, but just throwing it out there. I didn’t mean to draw attention specifically to this method.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss