tc39 / proposal-partial-application

Proposal to add partial application to ECMAScript
https://tc39.es/proposal-partial-application/
BSD 3-Clause "New" or "Revised" License
1.02k stars 25 forks source link

"Excess arguments" should be passed through #38

Closed mikestopcontinues closed 3 years ago

mikestopcontinues commented 4 years ago

I'm very excited for this proposal, but I find this line troubling:

Given f(?), excess arguments supplied to the partially applied function result are ignored.

Since Javascript has variadic functions, I think this breaks the spirit of the language. Excess arguments should also be passed through. For instance:

const sum = (...args) => args.reduce((a, b) => a + b, 0);
const partialSum = sum(1, 2, ?);
const finalSum = partialSum(3, 4, 5);

I would expect the sum to be 1 + 2 + 3 + 4 + 5, not 1 + 2 + 3. I believe that discarding excess arguments actually limits the potential for the operator, as one always has the option to pass fewer arguments (or clamp the function), whereas one cannot force a clamped function to accept more arguments later.

hax commented 4 years ago

There is a ... idea for that, see #18 .

mikestopcontinues commented 4 years ago

Thanks Hax, I was partly aware of the spread controversy, and I'm similarly on the side of leaving it out of the spec. I think it would be a mistake to require a special operator for JS to behave in the expected way (variadic functions).

rbuckton commented 4 years ago

The intent for this proposal is that all unbound (i.e., placeholder) arguments are explicit. For example, today array.map(parseInt) is problematic because map passes the index as the second argument to parseInt which parseInt can then interpret as a radix, resulting in unexpected behavior. array.map(parseInt(?)) does not have this issue, as we have explicitly invoked parseInt with one placeholder. This is akin to x => parseInt(x). The ... placeholder would explicitly allow excess arguments to pass through.

rbuckton commented 4 years ago

Also, it seems easier to me to implicitly forbid excess arguments and later add a syntax (i.e., ...) to explicitly pass them than the reverse: to implicitly pass excess arguments and to devise a syntax to explicitly forbid them.

mikestopcontinues commented 4 years ago

I'm torn on this. On the one hand, I can't help but see the usefulness of a built-in nary(n, fn) syntax, but on the other hand, I think it conflicts with intuitions about JS—more likely to be a problem for devs and less likely to be approved by the committee.

Another part of the issue rests on whether n-arity issues or variadic issues come up more often. I'm inclined to think the later, as the spread operator has encouraged more libraries to rely on variad-ism. Explicit passing would thwart that.

Of course, maybe I'm off the mark with the committee's intuitions about the language. Have you had any feedback about what's likely to pass? And what are your thoughts on that particular point?

rbuckton commented 4 years ago

Another part of the issue rests on whether n-arity issues or variadic issues come up more often. I'm inclined to think the later, as the spread operator has encouraged more libraries to rely on variad-ism. Explicit passing would thwart that.

Keep in mind that much of the community has also moved to using arrow functions wherever possible, and arrow functions require an explicit rest argument declaration as you cannot access the arguments of an arrow function.

ljharb commented 4 years ago

much of the community has also moved to using arrow functions wherever possible

I think this is too strong a claim, but it's a very good point that arrow functions do not allow for implicit variadism.

mikestopcontinues commented 4 years ago

I have definitely seen the rise of arrow functions, though I don't think it's explicit variadism we're looking at, because it's used on the parameter-side of the function, rather than the argument side.

A given function's developer is free to change how he uses parameters without affecting how a function's user uses it. I've certainly come across cases where I've generalized a function's logic by growing the spread to encompass earlier args. This suggests it isn't explicitly enabling variadism, but rather, explicitly naming the variable.

Similarly, regardless of whether the developer uses or names the variadic params, JS isn't going to throw an error for a user passing greater or fewer than the specified args. The language is designed to allow for high flexibility, and even if some developers prefer to limit themselves to one paradigm, it's un-JS to limit other developers freedom to use a different one. This is why I see swallowing arguments as something that definitely wouldn't fly, regardless of the added niceness of doing so.

rbuckton commented 3 years ago

Excess argument pass through is something we do not want by default in this proposal. Instead, we have introduced the ... placeholder which allows you to explicitly indicate that you want to pass in excess arguments, and where those excess arguments should be placed within the argument list.

ljharb commented 3 years ago

Will you be able to do f~([...]) to indicate that i want the excess arguments wrapped in an array literal before being passed?