-
Notifications
You must be signed in to change notification settings - Fork 110
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
What is the current status? #157
Comments
The F# style pipeline isn't appending or injecting anything to the end, though. It calls the right-hand side function with exactly one argument. I'd say that it is very common within JavaScript libraries and other codebases (at least in those that I've worked in), to have function signatures look very much like those in Elixir. That is, taking the "data" argument, be it a collection, string, whatever, as the first argument and then possibly some other arguments after it. On its own, I find the F# proposal hard to like because JavaScript functions are not automatically nor even commonly (in my experience) curried, which means that using an arrow function around the RHS is probably going to be a common need. I agree that the partial application proposal would largely solve this issue, but then with the partial application, I'm sort of starting to question the need for the pipeline operator at all. Is person.score
|> add(7, #)
|> boundScore(0, 100, #)
|> sendScoreToServer(person.id, #)
|> await
|> createNotification(person.username, #)
|> ScoreNotification.show(#) much better than pipe(
person.score,
add(7, #),
boundScore(0, 100, #),
sendScoreToServer(person.id, #)
).then(pipe(
createNotification(person.username, #),
ScoreNotification.show(#)
)); 🤷♂ I guess it's a little neater. |
I understand that the pipeline operator does not inject the current operated value into the last argument of the functions you pipe to. I never said that...I just said that the F# style was more "in line with" how JS arguments already work...that is, additional arguments flow into the end of the arguments list (vs. into the beginning of the arguments list, a la Elixir). As for why we would need a pipeline operator vs. just a pipe function. There are actually several other issues on this proposal that cover that topic in depth, and explain why an operator is beneficial and better than just a pipe function. The least of which is that pipe functions tend to be arbitrarily defined and ad-hoc, and thus inconsistent, but more importantly that an operator is easier for engines to optimize. There are definitely benefits to actually having the operator vs. using a pipe function. The F# proposal is far more flexible and adaptable than the Smart proposal, and when combined with the partial functions proposal (which is itself much more broad than just pipes), I am honestly not sure why the Smart proposal is even still in the running. |
Going to have to dive into this in more depth later, but I'll quickly point out that Partial Application is hardly a done deal, and tying the success of F# to Partial Application makes getting the former less likely. I wouldn't be advocating for the F# version if I thought it required Partial Application to be ergonomic, and I wouldn't assume PA is going to land. F# should stand on its own, imo. |
@jrista
Can you show some actual examples to back up these assertions you're making? Also, there are many more examples where smart just "works" where F# requires intermediate functions. |
const result = 5 |> x => x + 2 would be the F# approach. In this scenario, the engine could optimize away the arrow function; in fact, the babel plugin currently does this. |
You have artificially complicated the F# case here by implementing add, whereas you simply computed the result with smart. Either devilishly clever, or you seem to be missing the optimal F# case: const result = 5 |> a => a + 2 Would be the closest to the Smart version you created. Now if we use the add function, then smart doesn't look any better really than F# with partials: const add = (a, b) => a + b;
const result = 5 |> add(2, ?);
const result = 5 |> add(2, #); We do have another option with F#, though...one that is a bit cleaner for those who like curried functions or point-free code: const add = a => b => a + b;
const 5 |> add(2);
const 5 |> add(2)(#); In this case, Smart gets a little ugly and needlessly verbose where F# works like most functional languages do and if you take it to the fully point-free level, is very descriptive: const addTwo = add(2);
const 5 |> addTwo; Not everyone likes point-free coding, but there are those who do. It's an option with F#...not an option with Smart. I DO think F# stands on its own. As I said before, it is very flexible and works in many ways, and can be used like the above anonymous case, with curried functions (for which entire libraries exist, such as Ramda, with both the ability to curry any function as well as an extensive collection of ready-made curried functional utility functions), etc. What I do not like about Smart is there IS the Partials proposal, and at some point it'll probably go through to stage 3. If Smart becomes the pipeline proposal, then suddenly we have one way of doing partials with pipes, and another "standard" way for all the rest of JS... |
@jrista thanks for going into more detail. I tried this with babel setting the smart option on, and it seems to work. Does this alleviate one of the concerns you mentioned for smart? Am I missing something?
|
@aikeru That does work. This does not: const add = (a) => (b) => a + b
const result = 5 |> add(2) // Error in smart This requires a topic token. This style of point-free is not really feasible in Smart, although we have had some discussion about dropping some of the bare style restrictions (bare-style is currently only simple identifiers, member access or bracket access–anything further requires a topic token in order to avoid footguns). |
@aikeru My concern with Smart is that: a) There ARE cases where smart cannot do everything F# does I would say b is a key concern as if/when Partials goes through, then we have pipelines that are incompatible with them and require the use of a special template. I think that inconsistency would be bad. It would be confusing, and inconsistencies are things that ultimately make languages hard to use and possibly even broken in one way or another. Again, I don't think that F# is necessarily contingent per-se on the Partials proposal. However, I think that F# and Partials go together much better than Smart and Partials, and would avoid the inconsistency issues. I mean, we are all but guaranteed to have people confused about which template token to use depending on context..."is it #, or ?", and "why do we have two tokens?", "why can't I use ? in my pipeline?", etc. |
It seems like the differences boil down to this...
...and both could benefit from the placeholder. |
@jrista My assumption is if Smart advances, Partial Application is probably dead as a solo proposal. There are a number of follow-on proposals for Smart that would address the problem space Partial Application seeks to address. Smart is thus more broad as a proposal, as it's intended as a foundation to build on, whereas F# is a small, focused proposal. @aikeru Loosely, yes. It's my belief that the latter is superior to the former because it builds on syntax that exists (the arrow function) instead of introducing new syntax. |
I guess also, personally anyway: c) Smart doesn't do point-free very well (eh, kinds sorts not fully there) I do like the point-free style in the pipeline. I've done some F# coding, and have been playing with other functional languages for a while now. If I had to choose a particular method, I'd choose the point-free approach with curried functions over any of the alternatives. I am also a realist, though. I understand that JS is not purely functional, and as much as I would like it to have the capability of being purely functional, in most real-world contexts some blend of functional and other paradigms are most likely going to need to be used. Hence my great interest in partial function application. Sometimes, you may just not have curried functions, nor be able to create curried versions of every function. Some libraries (i.e. Ramda) that can curry sometimes do so in such a manner that breaks a function's compatibility in other contexts, etc. Being able to partially apply functions in any context, not just a pipeline, would help blend the boundary between highly functional code and code, say from libraries & frameworks, that is not particularly functional or not functional at all. |
@mAAdhaTTah That is rather concerning. :\ I guess I feel that features like partials should be their own proposal, compatible with the language in general...not just with a pipeline. Partial function application is useful in many contexts. I am rather wary of broad all-encompassing language features that, while they may support many features themselves, outside their explicit context you don't have them... |
Agreed! (With the general concept here...modular syntax that builds on each other, rather than a monolithic syntax that introduces new ways of doing things). |
I would encourage you to read through the proposals, specifically Pipeline Functions: https://github.com/js-choi/proposal-smart-pipelines/blob/master/additional-feature-pf.md The idea is the context in which you'd reach for and use pipelines becomes a lot broader with the introduction of these follow-on features. That said, I'm Team F#, so it's possible I'm not explaining Smart as well as a supporter would. |
I have read the proposals. I think you are referring to things like bare construction and await, pipeline funcs, pipe try/catch, etc? I'll grant, many of these proposals sound very handy... I guess that is my express concern. That all these features basically force you to use the pipeline in order to leverage any of the enhanced functionality. I'm not sure that would really be the best direction for the language to go... I'm a big fan of modularity and composability. You nailed it with the comment about arrow functions. They are an existing feature of the language, and they blend right in with F# pipelines if you need them. Partial functions would be the same way, a language feature (vs. a pipe feature) that would work anywhere in the language, and they would blend right in with F# pipelines if you need them. There is such an immense amount of JS code in the world, with a massive amount of JS coders of all skill levels ranging from very basic to highly advanced. I think language features that are simple, highly targeted, well defined, and can integrate into the language at large are ideal. I guess that is my general concern with Smart overall...it feels somewhat orthogonal to how JS has been done so far (modular), putting advanced features within a bit of an ivory tower (segregated, isolated and lofty) within JS as a whole, rather than integrating with it at large. |
That is basically my view as well. Obviously, the power provided by this collection of proposals is attractive as well, so I understand its support. To get back to your original question: The current status is the F# & Smart proposals (as well as Minimal) have been implemented in Babel. The next step is for people to use the proposals in the real world and provide feedback to the committee as to which proposal the community prefers. I'll also mention there is a contingent of the committee that prefers the bind operator for this kind of pipelining, and there's a contingent that is concerned about the language's syntax budget overall and opposes new syntax for pipelining in general. We've done some user surveys, I believe another survey is in the works, and I personally am working on a talk that I plan on bringing to the meetups around NYC to discuss the proposals, their status, and solicit feedback from the community. So there's still a lot to do before this advances, so plenty of time to get this right. |
@mAAdhaTTah Thanks! I can understand concerns about syntax budget. There are many proposals out there and the more complex the language, the tougher it is to parse. That said, functional programming is really gaining traction in the JS community. A functional pipeline (especially F# style with its point-free compatibility) would be incredibly useful. And as both proposals state...code becomes so much cleaner with the pipeline. Well, I guess we wait and see. And participate. ;) See ya around! |
What's the preferred way of providing feedback to the committee? |
@yeedle Goooood question. Most people have been opening issues on GitHub to provide feedback, unless you find an open thread with the issue you want to discuss. Or just comment here. We should probably figure that out. |
F# style + partial application still can not deal with some cases which smart style can:
We need arrow functions in first two cases which seems verbose, and we could use |
@hax |
@mAAdhaTTah
|
@hax I dont believe you can reach that edge case. Inside an async function you cannot redefine the keyword async () => { function await() {} } gives the error
IMO |
@andykais They couldn't turn it into a reserved keyword everywhere because it would break BC (functions named @hax Oh weird... TLA is new(ish) compared to when we first came up with the proposal. |
Actually, how does TLA handle |
TLA is only in Modules, in which await is a reserved word. pipeline would be available in Scripts, in which it is not. |
Is there some way to find out if this is going to get to stage 2 (AFAIK it's in stage 1 now)? Is there a meeting at some point where these decisions get made (a meeting minutes or meeting outcomes)? I really like F# but mainly work in JS (both client/server) and think this would be a great addition to the language (and also PA). |
The champions would have to put it on a meeting agenda, at least 10 days in advance, and then the committee would have to have consensus on advancement. Stage 2 would likely require having already selected a single form of the proposal. |
@aadamsx Shoot me an email, which is available in my GitHub profile, and let's figure out what we need to do. |
I too am looking forward to getting this on the agenda. That said, we do need to work the process. I have grave concerns about smart pipelines, as they suck so much rich functionality SOLELY into the pipe, which IMO is antithetical to the existing nature of JS, and its flexibility in being able to be used in multiple ways. I very much want a partial apply feature as well, but I most definitely do NOT want that feature to be explicitly restricted to a smart pipeline. Problem is, that is exactly what smart pipelines are about, segregating all this new rich functionality solely within the pipeline operator. This issue definitely needs to be hashed out by the community before we move forward. |
@jrista respectfully your comments above seem like a distraction.
I don't think the JS community should consider the "smart pipelines" style, but instead focuse on the F# style.
Partial application (which is what I think you're referring to here) is a separate proposal and has nothing to do with the Pipeline Operator F# style proposal being implemented. They could work together, but are not dependent.
The F# style of the pipeline operator is what I think the JS community should focus on and move forward with, and not worry about "hashing out" anything to do with "smart pipes" before moving forward. |
@mAAdhaTTah I sent an email you to about 2 days ago with an offer to help without response, maybe my email went to spam... |
@aadamsx No, I got it, just been busy, sorry. |
@aadamsx The problem is, there is no consensus yet in this proposal that F# is the actual choice. I agree, I prefer F# style...but, that decision hasn't actually been made as far as I know. That decision NEEDS to be MADE for this proposal to move forward. Regarding partial application, if the champions choose Smart Pipelines, then partial application is a part of that...meaning, partial application would ONLY work within the pipeline, and the other proposal would be dead. Hence my concerns. |
The vote to drop smart pipelines issue shows a bit of a consensus #158 |
I don't know how consensus is determined, or a decision is made. But I like the F# style. Would be great to see this move past analysis paralysis. |
Community consensus, yes. I haven't seen champions chime in on this in a while, and it sounded (at least in the past) like some of them were pretty staunchly in favor of smart pipelines. I agree though...it would be great to split off smart pipeline into its own proposal, keep F# style here, and get past the paralysis. I'm much more in favor of a modular approach to the features we would need to really make JS, pipelines, etc. into a very expressive, functional language. They just need to be separate proposals that don't lock users into the pipeline...as not everyone wants to program that way, like the partial application proposal. |
Shouldn't community consensus be enough to move this forward? There are champions on both sides of the aisle. The community (at least the engaged one) seems to be preferring F# style over Smart for whatever reason. |
I would hope... I would really love for this to move forward, but that consensus thread was from November last year, some 5 months ago. No traction from the people who actually CAN move this forward, sadly... I don't know what that means. |
Who are those people? TC39 members? @littledan? Perhaps we can reach out directly? |
To move forward, this proposal would not just have to pick a solution shape “that the community prefers” - it also has to prepare an ironclad, persuasive argument for why that shape is the only one that will make sense forever (including outlining potential extensions, or which extensions are precluded). It would also have to make a compelling argument to those on the committee (including browsers/engines, who have to implement it) that the cost of adding and shipping syntax is worth it, and that’s something some delegates are very inclined to not consider worth it for any new syntax. What I’m describing is roughy part of every proposal’s advancement process, to be clear - but in this proposal’s case, where there’s more than one reasonable (and quite disparate) solution shape, such proposals absolutely run the (correct and reasonable) risk of stalling for many years at a time, or longer. |
@ljharb Thanks for being clear about that. This is understood, hence the reason why I think there is a push to get this proposal to the point where there is just one shape. At least once a choice is made, then the proposal could move forward with everything else that needs to be done. |
It sounds like what needs to be done is create an argument for why F# style is the correct choice. If we can formalize that argument, we can at least present that to @littledan and ask that he move forward with it. (E.g. iron out the specification, describe edge cases, etc) If you dig back through the issues in this repo, there are a lot of opinions. I think most cases are already argued so its largely a matter of addressing the open ended issues and summarizing and simplifying decisions into a single document. |
Is there another proposal that was in a similar position (stalled for a long time with apparent decision paralysis) and wound up successfully moving forward that could be used as a model? |
The optional chaining operator kind of spun its wheels for a good while. Lot of alternative ideas for the operator kept cropping up. Eventually another community consensus issue popped up, and there ended up being overwhelming support for the originally proposed |
@matthewwithanm Class fields. Pattern matching. Decorators. Do expressions. Async/await. Almost every syntactic proposal has been in this position; there's nothing unique about pipeline in this regard. |
@ljharb At this time, pattern matching, decorators and do expressions don't seem like good examples of proposals that "wound up successfully moving forward" :) |
@noppa ah sorry, i missed that part :-) you're right. altho i've just taken over championing pattern matching, so we'll see :-p |
Again, a community vote like that is not a sign of consensus. It can be an input to the committee process, but all such polling must be taken as merely that, an input. I've done a lot of polling to help figure out design questions for CSS features, and if I took the highest-voted answer every time, or even just when one answer was an overwhelming winner, I'd have designed things badly. A notable wrinkle as well is that it's important to note where the polling votes are coming from, and how the question was asked and advertised. It's real easy to get a big group coming in from a particular partisan's cheerleading, which leads to a lopsided result. It's also very easy for a question to be asked in a way that favors one result, or that omits important details. And elaborating on that final note, most such community polls' votes are made by people giving an off-the-cuff immediate opinion. Some people spend time reading background material and making an informed choice, but most choose the one that makes the most immediate sense to them after having read the minimum amount of text on the page to decipher the choices. For some types of questions (figuring out aesthetics, or naming decisions), that's just fine, and the results can be a really strong input into what the final decision should be. For others (where the arguments each way are subtle, or there are broad-reaching concerns that are important, like cross-language consistency), it's not at all useful, and the poll ends up mostly being noise. So all that is to say: feel free to poll away, but don't expect that to be a magic bullet for solving an impasse. (I consider this topic to be one of the latter cases, btw - a complex topic concerning cross-language consistency. Off-the-cuff answers are unlikely to be very useful, as this requires careful consideration and balancing of some pretty subtle language-design issues.) (That all said, the poll is currently overwhelmingly in favor of my preferred solution (smart mix), so that's nice at least.) |
I don't think optional chaining op is a good example. The main argument of optional chaining is just operator token (whether |
I'm excited for this renewed interest in pipelines! Seems what we need right now is more working implementations so people can code, test and provide feedback on these new features. I'll dig up my dev environments and rebase my TypeScript pipeline & partial application branches to master today. While Babel plugins are important for production code, a lot of development is done with TypeScript and having red squigglies in your perfectly valid code bugs the hell out of people and will attach negative association to the feature. Neither does it help that all autocompletes and type information just vanishes from the point where you start using pipelines or partial application. The development environment for JS has changed dramatically in just a couple of years and I consider first-class support in TS for these two crucial! The TS partial application feature is functional, but needs more eyes. We've actually had a surprising amount of articles written on the features during last couple of months. But it's just hot air so far. Users need to set up babel, install plugins and endure the crippled editor to test the feature. They can't test whether the types are resolved as they expect. We need accessible on-line playgrounds with the features. I'm working on having draft PRs for these in TypeScript repo. |
Made the Partial Application TypeScript draft PR It does need quite a bit of work still. To test it in your project, add following to your package.json:
and then run |
Now there's also TypeScript draft PR for Pipeline Operator support. Also has instructions on how to use it in your own project. This mainly implements parts of the minimal proposal. All feedback is welcome! I'm going to create a draft PR that has both pipeline and partial application so people can play around with it and use them. |
Closing this issue, as the proposal has advanced to stage 2 with Hack-style syntax. |
Just curious what the current status of this proposal is. It's shown that there is a conflict between F# style and Smart style. In most cases that I come across, it seems that F# style is preferred over Smart. It also appears that Smart is largely only preferred since it has a template that can be referenced throughout the pipe.
With the partial functions proposal, it seems like that largely solves the "template/placeholder" problem for F# style. The F# style also generally seems more flexible, more modular, more like other pipelines in other languages, can be used with curried functions, anonymous functions, partial functions, etc. The F# style can be extremely clean and concise with curried and/or partial functions. The F# style is explicitly preferred by the partial functions proposal. The F# style is also more in line with how javascript generally works, with extra arguments appended to the end (and accessible in
arguments
if necessary), rather than injected at the beginning (as in Elixir).Given that partial functions is an existing proposal and would bring partial application of functions to JavaScript in a much more general sense, rather than explicitly and only in the pipeline... What are the remaining arguments FOR the Smart syntax? If there are no real remaining solid arguments for the Smart syntax...what would it take to get this proposal past that deadlock so it can actually progress?
Functional programming with JS has come a long way, and is becoming more popular. A pipeline operator would be a wonderful replacement for ad-hoc pipe/compose/chain/forwardApply functions. It would clean up and simplify a lot of functional code. Combined with partial functions and pattern matching, I think functional programming with JavaScript would truly come of age.
The text was updated successfully, but these errors were encountered: