-
Notifications
You must be signed in to change notification settings - Fork 110
Should we do infix :: instead? #107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
This sounds like two suggestions in one:
|
I'm not sure what this suggestion is; it sounds like you're saying we should support the bind operator instead of pipeline. |
My point is not :: vs |>, but rather to revive the bind operator (which was known as infix ::) and do it instead of 1) pipeline, 2) hidden/private methods, and 3) so-called extension methods or extension interfaces. We can postpone arguing about what it looks like.
Regarding the purposes addressed by the pipeline operator specifically, I won't argue. My point rather is that the bind operator satisfies most of that need as well as many others. IMO the bind operator pulls its weight.
Yes, that is what I'm saying. And also instead of private/hidden methods. Besides these, it also continues to be as good as it always was at its original motivations. When we find ourselves repeatedly inventing new things for special cases of the needs bind would have satisfied... |
@erights: As background, there are now five competing pipeline proposals, some of which are in rapid flux, and each of which addresses a different set of use cases. I myself am the author of Proposal 4: Smart Pipelines. This new issue does not address any one of these three specifically; rather, the issue’s premise is that a function-binding operator would address the major functionality of all five of the pipeline proposals—unless I am misunderstanding its language. Let me preface this by saying that I am a big fan of you and your work, Dr. Miller; it is an honor to communicate with you. Having said that, I do not yet see how the claim above (“a function-binding operator would address the major functionality of all five of the pipeline proposals”) could be correct. The primary functionality and purpose of the pipeline operators in all five proposals are to untangle deeply nested expressions, especially deeply nested unary function calls, into linear, unidirectional sequences of postfix steps. And a function-binding operator, such as the previously proposed infix It is a fait accompli that numerous JavaScript APIs, including the DOM, have functions that are designed to transform values as arguments—not as method callees. For instance, the WHATWG Fetch API uses a global There are numerous other functions similar to Many APIs also have methods that do use their callee object, while still requiring arguments that may be deeply nested. One such API that readily comes to mind is the Selenium WebDriverJS library. Bearing this fait accompli in mind, then examining the rewritten example given in this issue’s original post immediately shows the problem: The use of its solution requires the modification of these already-written functions that do not use The solution therefore cannot be used with WHATWG Fetch. It cannot be used with WebDriver methods. It cannot be used with most functions from Underscore, Lodash, Ramda, RxJS, and numerous other popular third-party libraries whose functions do not use It can only be used with functions that happen to be written such that they use (And for the smart-pipelines proposal specifically, a function-binding operator also does not address its other use cases, including terse function composition, terse function partial application, and terse method extraction. The smart-pipelines explainer, in fact, already discusses the intersection and orthogonality of smart pipelines with the A function-binding operator may well address use cases from private class methods (zenparsing/js-classes-1.1#38). The function-binding operator would certainly address extension methods. But not only would a function-binding operator not address “some of the functionality” of the five competing pipeline proposals—it would not address any of their functionality. (To review, the major functionality here is the untangling of deeply nested expressions—in particular, unary-parameter function calls—which is orthogonal to matters of function binding.) Again, I am a huge fan of your work; it is an honor. |
What it does address, it addresses with a much simpler syntax than whatever will come out of the pipeline proposals. If it were usable with arrow functions, I think |
Hi @js-choi , first, thanks for the kind words! Always appreciated. I confess that I am responding here without having read all the proposals deeply. Please continue to object, correct, and question if my responses seem to miss the points of some or all of the pipeline proposals, thanks. Let's start with the stated required goals:
Given that the composition is via function adapt(f) {
return function(...args) {
return f(this, ...args);
};
} would be useful. Returning to the original example, without rewriting function doubleSay (str) {
return str + ", " + str;
}
function capitalize (str) {
return str[0].toUpperCase() + str.substring(1);
}
function exclaim (str) {
return str + '!';
} we could use an adapter such as let result = "hello"::adapt(doubleSay)()::adapt(capitalize)()::adapt(exclaim)(); If indeed most things need to be adapted, as in the above example, the terseness is lost. But the main benefit I see in the pipeline proposals is not the terseness, but the left-to-right composition. @charmander
yes
yes |
This isn't really true, depending upon the proposal. The Smart Pipeline's placeholders can put in any argument position. F#-style probably would, but I don't really a large difference between requiring an Given that the I also believe there were other issues @zenparsing pointed out on this repo; I'll see if I can find them. Update: Found his comment here: #101 (comment) |
I’m not sure which of the five competing pipeline proposals you are referring to, but I think all of them have fairly simple syntax, though each with various tradeoffs. The Core Proposal syntax grammar of Proposal 4: Smart Pipelines can literally be written on a single notecard; the syntax grammar of the original proposal is similarly tiny. In the end, they’re all infix operators, just like how the binding operator is a binding operator. I’m interested in reasons that you feel any or all of the five proposals may be overcomplex despite their tiny grammars—but, in any case, those reasons are probably not relevant to this particular issue. Feel free to open a new issue in this repository; be sure to specify which of the five proposals you are discussing. In any case, the use cases that a binding operator might address (such as private class methods and extension methods) is not relevant to the uses cases that a pipeline operator would address: unidirectional postfix application, as well as (for smart pipelines) function composition, partial application, and method extraction.
If you need a brief overview of the two frontrunner proposals by @mAAdhaTTah and me, take a look at the unfinished presentation for TC39 London next week that we’re working on. I’ve also written a detailed explainer document for smart pipelines that goes over their use cases, with many examples from real-world code.
I will address the rest of this comment below, but I am wondering how
@mAAdhaTTah is correct here. Although the original proposal and Proposal 1 (F-sharp Style Only with Bare Await) do focus on unary calls, Proposals 2 (Hack Style Only), 3 (Split Mix), and 4 (Smart Pipelines) all can easily deal with piping into arbitrary parameters—and, indeed, arbitrary expressions. This is something that binding alone simply cannot naturally address. That a third-party There is a fundamental impedance mismatch between the model of As an aside: Expression application (as with Proposals 2, 3, and 4) can address method extraction—for instance, with smart pipelines + Additional Feature PF: But even expression application does not address method binding, in which a value is applied to a function as its For more discussion about the relationship between pipelines and the bind operator, see @jakearchibald’s issue #101, as @mAAdhaTTah already linked above. Eventually, pipelining may support more abstract forms of composition. @tabatkins, @isiahmeadows, and I have been discussing such possibilities (see #106). This would be quite difficult to achieve if Thanks again for the disucssion, Dr. Miller. Let me know if you find the time to read the smart-pipelines explainer or spec. I’m looking forward to seeing it and @mAAdhaTTah’s alternative discussed next week at TC39. |
I wanted to share my opinion on this topic, however my post grew in size until I decided it's best to post it as a separate issue. The main point was that the features of Smart Pipelines are almost a superset of those of the Binding Operator despite they don't suffer the same problems that kept the Binding Operator stalled for ages. |
When we discussed pipeline in the March 2018 TC39 meeting, it seemed like the committee had a number of advocates for |
@littledan It feels like the use-cases for |
@jakearchibald I don't think the problems they are solving are all that different. Some libraries, like RxJS, may be able to adapt to any one of the two. As we were discussing in the March 2018 TC39 meeting, we only have so much budget to add punctuation while remaining intelligible. I'd rather figure out which pattern is more important, add that, and maintain skepticism for adding both, even as there is no hard blocking concern. |
My 2¢: I think The original I’m don’t have strong opinions on the actual shape of the operator. |
@surma I'm not sure I understand this bit:
Can you elaborate? |
Yeah, my bad! I was making a sweeping statement without thinking about the “smart pipeline operator”. Example: myObject |> add(4); The implementation of function add(val) {
return obj => obj + val;
} The “smart” version of the pipeline operator solves this: function add(obj, val) {
return obj + val;
}
myObject |> add(?, 4); but I think that’s quite magic and much farther away from what JS developers are used to, compared to how |
Yeah, F# Pipelines would require a new closure. Although I don't personally consider that drawback, I understand that's not universal. It's almost too bad we have a limited syntax budget, because I do think there's a combination of bind |
Would some sort of hybrid operator like |
@andrewbanchich Everything is open to discussion. If you have a more fleshed out idea that combines pipeline & bind, I might suggest opening a separate issue with the details. I was just pondering how something like that would look / work, but I'm concerned it would quickly stretch beyond the complexity of even the current Smart Pipeline. |
I was thinking since JavaScript has double and triple equals for equality comparison, we could have a similar interpretation of the pipeline operator like |
@andrewbanchich That doesn't sound like a good idea – people would argue whose operator is bigger 🤔 |
@m93a please keep comments appropriate and inline with our code of conduct. |
Closing this issue, as the proposal has advanced to stage 2 with Hack-style syntax. |
Uh oh!
There was an error while loading. Please reload this page.
I refer to the old infix :: bind proposal operator (TODO link needed), which satisfies some of the functionality people are looking for, from
Redoing the first example of this proposal: Given
...the following invocations are equivalent:
The text was updated successfully, but these errors were encountered: