Proposal: rest operator in middle of array

guest271314 guest271314 at gmail.com
Mon Jun 10 23:12:46 UTC 2019


The proposed pattern is already possible, as demostrated at the code at
https://esdiscuss.org/topic/proposal-rest-operator-in-middle-of-array#content-2
.

How does the code at that post specifically not provide the same
functionality as proposed?

On Mon, Jun 10, 2019 at 9:20 PM Ethan Resnick <ethan.resnick at gmail.com>
wrote:

> > This has come up several times and, while it seems pretty intuitive to
> me, not everyone seems to agree. You can check the archives for previous
> discussions.
>
> @Andy Perhaps you can provide some links? I found two
> <https://esdiscuss.org/topic/an-array-destructing-specification-choice#content-69>
> threads <https://esdiscuss.org/topic/early-spread-operator> — both 8
> years old — that talked about this, along with one more recent one
> <https://esdiscuss.org/topic/strawman-complete-array-and-object-destructuring>
> that didn't get very far. In the first two threads, commenters brought up
> one case where the semantics are unclear (i.e., when there are more listed
> binding elements than there are elements in the iterable), and there was
> some talk about implementation complexity. But there was also some interest
> from some big contributors to the spec. So I wonder if it's time to revisit
> this?
>
> > if you want to extend the function with additional args,
> > then you'll have to retroactively modify all existing calls to avoid
> off-by-one argcount:
>
> @Kai I'm not sure I follow. If the new argument is required, you have to
> modify all existing calls whether the new argument goes at the end or as
> the second to last argument. If the new argument is optional, then adding
> it as the second to last argument doesn't break existing calls at all,
> assuming the function accounts for the fact that the optional arguments are
> all the ones after the initial required ones, and up until (but excluding)
> the last one. The syntax I'm proposing makes adding such extra arguments
> easy. In other words:
>
> ```
> function pad(targetLength, ...opts, data) {
>   const [paddingChar = " "] = opts;
>   // pad data with paddingChar to targetLength;
> }
> ```
>
> would, with the addition of an optional "meta" arg, become:
>
> ```
> function pad(targetLength, ...opts, data) {
>   const [paddingChar = " ", meta = { /* some default */ }] = opts;
>   // pad data with paddingChar to targetLength;
> }
> ```
>
> More importantly, though, this data-last calling pattern has a long
> history, and there are some cases where it's the best solution. My use case
> was similar to the common one, namely, that I was building a data pipeline,
> with the "settings" arguments partially applied from the left to create the
> function to use in each step. (And, in my case, I was building each
> function in a DSL where it would've been very inconvenient to add
> arbitrary-order partial application, even if JS were to add something like
> that <https://github.com/tc39/proposal-partial-application>.)
>
> Given that functions where the last argument is significant probably
> aren't going away, it'd be nice imo if the JS syntax supported this better.
>
> On Fri, Jun 7, 2019 at 7:11 PM kai zhu <kaizhu256 at gmail.com> wrote:
>
>> it matters when you have to debug/inherit *other* people's code (and
>> clean up their mess).  i wouldn't enjoy debugging unfamiliar-code that used
>> this feature (admittedly, its my subjective opinion).
>>
>> the maintainability argument stands -- its counter-intuitive in
>> javascript that appending extra args to a function re-arranges
>> arg-positioning and invalidates existing calls.
>>
>> debuggability is subjective i agree.
>>
>> p.s. - in general, i don't see what *real* painpoint rest-operator
>> actually address, that couldn't be solved with `arguments`.
>> variable-arg-length functions are not javascripty -- they frequently
>> require extra ux-workflow transformations like Function.p.apply or
>> Array.p.flatmap to the arguments being passed.
>>
>>
>> On Fri, Jun 7, 2019 at 10:07 AM Isiah Meadows <isiahmeadows at gmail.com>
>> wrote:
>>
>>> For your maintainability argument: adding extra arguments to those
>>> functions is something I almost never do. And you'd have the same
>>> exact issue with final rest parameters, just in a different position
>>> (in the middle as opposed to in the end).
>>>
>>> For debuggability, I don't see how it'd be a major issue unless you
>>> already have an excessive number of *positional* parameters. In my
>>> experience, the debuggability issues arise approximately when there's
>>> just too many positional parameters, and factoring out the rest
>>> parameter to an array doesn't really help this situation much. (That's
>>> when object destructuring comes in handy.)
>>>
>>> So not convinced either is any different than what it's like today.
>>>
>>> Also, you aren't obligated to use a feature just because it exists - I
>>> hardly ever use proxies, for instance, and I rarely need maps beyond
>>> what objects give me, so I don't normally use them unless I need to
>>> have reference types or mixed types as keys.
>>>
>>> -----
>>>
>>> Isiah Meadows
>>> contact at isiahmeadows.com
>>> www.isiahmeadows.com
>>>
>>> On Thu, Jun 6, 2019 at 2:22 PM kai zhu <kaizhu256 at gmail.com> wrote:
>>> >
>>> > -1 for maintainability and debuggability
>>> >
>>> > 1. maintainability
>>> > if you want to extend the function with additional args,
>>> > then you'll have to retroactively modify all existing calls to avoid
>>> off-by-one argcount:
>>> >
>>> > ```js
>>> > // if extending function with additional args
>>> > function pad(targetLength, ...opts, data) ->
>>> > function pad(targetLength, ...opts, data, meta)
>>> >
>>> > // then must retroactively append null/undefined to all existing calls
>>> > pad(1, opt1, opt2, "data") ->
>>> > pad(1, opt1, opt2, "data", null)
>>> > ```
>>> >
>>> >
>>> >
>>> > 2. debuggability
>>> > when debugging, it takes longer for human to figure out which arg is
>>> what:
>>> >
>>> > ```js
>>> > // function pad(targetLength, ...opts, data)
>>> > pad(aa, bb, cc, dd);
>>> > pad(aa, bb, cc, dd, ee);
>>> >
>>> > // vs
>>> >
>>> > // function pad(targetLength, opts, data)
>>> > pad(aa, [bb, cc], dd);
>>> > pad(aa, [bb, cc, dd], ee);
>>> > ```
>>> >
>>> >
>>> >
>>> > On Thu, Jun 6, 2019 at 11:54 AM Ethan Resnick <ethan.resnick at gmail.com>
>>> wrote:
>>> >>
>>> >> Long-time mostly-lurker on here. I deeply appreciate all the hard
>>> work that folks here put into JS.
>>> >>
>>> >> I've run into a couple cases now where it'd be convenient to use a
>>> rest operator at the beginning or middle of an array destructuring, as in:
>>> >>
>>> >> ```
>>> >> const [...xs, y] = someArray;
>>> >> ```
>>> >>
>>> >> Or, similarly, in function signatures:
>>> >>
>>> >> ```
>>> >> function(...xs, y) { }
>>> >> ```
>>> >>
>>> >> The semantics would be simple: exhaust the iterable to create the
>>> array of `xs`, like a standard rest operator would do, but then slice off
>>> the last item and put it in `y`.
>>> >>
>>> >> For example, I was working with some variable argument functions
>>> that, in FP style, always take their data last. So I had a function like
>>> this:
>>> >>
>>> >> ```
>>> >> function match(...matchersAndData) {
>>> >>   const matchers = matchersAndData.slice(0, -1);
>>> >>   const data = matchersAndData[matchersAndData.length - 1];
>>> >>   // do matching against data
>>> >> }
>>> >> ```
>>> >>
>>> >> Under this proposal, the above could be rewritten:
>>> >>
>>> >> ```
>>> >> function reduce(...matchers, data) { /* ... */ }
>>> >> ```
>>> >>
>>> >> Another example: a function `pad`, which takes a target length and a
>>> string to pad, with an optional padding character argument in between:
>>> >>
>>> >> ```
>>> >> function pad(targetLength, ...paddingCharAndOrData) {
>>> >>   const [paddingChar = " "] = paddingCharAndOrData.slice(0, -1);
>>> >>   const data = paddingCharAndOrData[paddingCharAndOrData.length - 1];
>>> >>
>>> >>   // pad data with paddingChar to targetLength;
>>> >> }
>>> >> ```
>>> >>
>>> >> With this proposal, that could be rewritten:
>>> >>
>>> >> ```
>>> >> function pad(targetLength, ...opts, data) {
>>> >>   const [paddingChar = " "] = opts;
>>> >>   // pad data with paddingChar to targetLength;
>>> >> }
>>> >> ```
>>> >>
>>> >> I'm curious if this has been considered before, and what people think
>>> of the idea.
>>> >>
>>> >> Obviously, if `...a` appeared at the beginning or middle of a list,
>>> there would have to be a fixed number of items following it, so a
>>> subsequent rest operator in the same list would not be allowed.
>>> >>
>>> >> Thanks
>>> >>
>>> >> _______________________________________________
>>> >> es-discuss mailing list
>>> >> es-discuss at mozilla.org
>>> >> https://mail.mozilla.org/listinfo/es-discuss
>>> >
>>> > _______________________________________________
>>> > es-discuss mailing list
>>> > es-discuss at mozilla.org
>>> > https://mail.mozilla.org/listinfo/es-discuss
>>>
>> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20190610/3393915d/attachment-0001.html>


More information about the es-discuss mailing list