Skip to content
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

Discussion: Proposal Mixes #89

Closed
gilbert opened this issue Feb 1, 2018 · 108 comments
Closed

Discussion: Proposal Mixes #89

gilbert opened this issue Feb 1, 2018 · 108 comments

Comments

@gilbert
Copy link
Collaborator

gilbert commented Feb 1, 2018

Hi all, I've just updated the wiki with the current status of all proposals so far. This thread specifically is for exploring the possibility of mixing together the two main proposals (F-sharp style and Hack style). Please visit and read that page for details.

@js-choi
Copy link
Collaborator

js-choi commented Feb 2, 2018

See also #75 and #84 for prior discussion on standardizing both styles’ operators.

@littledan
Copy link
Member

Great explanation there! The only other thing I'd like to see is a summary about how these are or aren't "forward-compatible" with @rbuckton's partial application operator, and what implications they'd have for the operator if compatible. It's OK if we decide that that's not a goal, but I'd like to be explicit about the tradeoff.

@pygy
Copy link
Contributor

pygy commented Feb 2, 2018

@gilbert thanks for the summary.

I'm surprised by the presence of await on its own line, I thought that |> await was meant to act as a composite binary operator of sorts. If I understand the current proposal, they could be moved to the line above without harm in all samples:

  |> (a => readDB(a, config))
  |> await

becomes

  |> await (a => readDB(a, config))

etc...

Do you mind if I add the #23 (comment) precedence proposal as a fifth option ("F# with lower precedence")?

@gilbert
Copy link
Collaborator Author

gilbert commented Feb 2, 2018

@littledan Sure, I added some bullets indicating compatibility.

@pygy For F-sharp style, |> await f was not chosen for two reasons: it behaves differently than |> (await f), and it presents an ASI hazard. Requiring it on its own line solves both these problems.

For the grammar point I think we should wait for an approval on its possibility from a tc member first. If approved, it would impact F-sharp usage sections instead of being a 5th option.

@pygy
Copy link
Contributor

pygy commented Feb 2, 2018

@gilbert thanks, I'm catching up... The master branch still has |> await f. I see #85/#83 now.

@js-choi
Copy link
Collaborator

js-choi commented Feb 3, 2018

Does this issue cover both the dual-operator Proposal 3: Split Mix and the single-operator Proposal 4: Smart Mix?

Because as far as I can tell, #75 already covers Proposal 4. The original post proposes a single pipeline operator that supports both F#-style tacit calling and Hack-style placeholder expressions.

@mAAdhaTTah
Copy link
Collaborator

@js-choi The conversation in #75 has bounced around quite a bit. With some concrete proposals to work off of, I think we should pick up both "mix" options here and close #75.


I really like "Smart Mix" with some bikeshedding over the token. Seems like a solid best of both worlds. Are dropping the closing-over behavior discussed elsewhere? I think it's simpler without it, but just want to make sure that wasn't overlooked.

@littledan
Copy link
Member

I like the Smart Mix option as well. I want to suggest a specific version of it, inspired by comments from @rbuckton:

  • Use ? as the placeholder, matching partial application
  • Include the await patch Spec |> await #85 ; no special behavior for yield
  • Add special support for |> .method()
  • Permit the placeholder only as a top-level argument of the function call, and not more deeply in an expression

This version would be cleanly forward-compatible with the partial application proposal as it currently is. IMO unless we want to argue that partial application isn't going to happen, we should try to make placeholders explainable as them. Of course it's fair game to propose changes to partial application, but I don't really see any changes as being necessary here with the above options.

@rbuckton explained to me that, even with the partial application proposal landed, it still may make sense to support a direct semantics for pipeline placeholders, to make it so that the anonymous partially applied function unobservable (e.g., through engine-specific exception handling APIs which sometimes expose sloppy mode function identities).

What do you think?

@gilbert
Copy link
Collaborator Author

gilbert commented Feb 5, 2018

@littledan What you're suggesting is not a mix, but F-sharp behavior with partial application built-in. The hack-style behavior is gone, thus the need for |> .method(). Not saying yay or nay, just wanted to make that clear.

@mAAdhaTTah
Copy link
Collaborator

@littledan Does this imply that arbitrary expressions, e.g. |> 'Hello' + ? are possible on RHS? That was also one of the defining features of the Hack-style proposal.

@littledan
Copy link
Member

@gilbert Yes, I see that it's different. Should we put it as a fifth option in the wiki?

@mAAdhaTTah No, this would be disallowed.

@zenparsing
Copy link
Member

IMO unless we want to argue that partial application isn't going to happen, we should try to make placeholders explainable as them.

Then I think we ought to have that conversation, because the forward-compatibility constraint is leading towards a bizarre set of special-case rules that I don't think anyone wants or needs.

@gilbert
Copy link
Collaborator Author

gilbert commented Feb 5, 2018

@littledan Yes, I think it would go well as "Proposal 1b", since it's F-sharp plus some features.

To be honest I think it might be the one that works for everyone. At least, for what I think you're talking about:

// Basic Usage
x |> f         //-->  f(x)
x |> f(?)      //-->  f(x)
x |> f(? + 1)  //-->  SyntaxError
x |> f(y)      //-->  f(y)(x)

// 2+ Arity Usage
x |> f(?,10)     //-->  f(x,10)
x |> f(?,10, ?)  //-->  SyntaxError?

// Async Solution
x |> f |> await       //-->  await f(x)
x |> f |> await |> g  //-->  g(await f(x))

//
// Arbitrary Expressions Option 1 (nothing special)
//
f(x) |> (a => a.data)           //-->  f(x).data
f(x) |> (a => a['my-data'])     //-->  f(x)['my-data']
f(x) |> (a => ({ result: a }))  //-->  { result: f(x) }

//
// Arbitrary Expressions Option 2 (special casing)
//
f(x) |> .data                   //-->  f(x).data
f(x) |> ['my-data']             //-->  f(x)['my-data']
f(x) |> (a => ({ result: a }))  //-->  { result: f(x) }

//
// Arbitrary Expressions Option 3 (generic placeholder)
//
f(x) |> (?).data           //-->  f(x).data
f(x) |> (?)['my-data']     //-->  f(x).data
f(x) |> { result: (?) }    //-->  { result: f(x) }

Restricting the placeholder to function argument positions is actually useful for more than just "forward-compatibility with partial app" – it allows ? to be the token without issue, since it can no longer be mixed within an expression. In other words, no more confusion with optional chaining or nullish coalescing.

But it still would be compatible with a partial app proposal that might look something like this:

var f   = ::g(?, 10)    // apply 10
var log = ::console.log // method extraction

Not that it needs to be compatible technically, but it should be compatible semantically.

@littledan
Copy link
Member

To be honest I think it might be the one that works for everyone.

This was my hope. The only downside, as @zenparsing points out, is unmotivated complexity if we don't have partial application.

Arbitrary Expressions Option 3 (generic placeholder)

I really like this option! It bridges the gap to get full expressiveness, without special cases. We can tell a simple story, that (?) is only available after |> since otherwise the scope is unclear. It's a Syntax Error if you get it wrong, anyway.

@js-choi
Copy link
Collaborator

js-choi commented Feb 6, 2018

As @gilbert and @mAAdhaTTah point out, this appears to be not a mix proposal but rather a variation of Proposal 1: F-sharp Style Only, with no opt-in Hack Style, because it forbids arbitrary expressions…

…except for the third option in #89 (comment), which appears to be the usual Proposal 4: Smart Mix but using a (?) nullary operator as its placeholder.

If that analysis is correct, I will add (?) to #91 and the wiki. But then would not x |> await (?) be the same as the x |> await special case? And x |> yield (?) would be valid too, right? What then would be the point of the await special case?

As for the first two options in #89 (comment), should they get their own issue, as a “Proposal 1b”? I can also add them to the wiki—though I am a priori not a fan of them, since they involve much syntactic special casing while losing much expressiveness.

It should be noted that option 3 can coexist with a ?-using partial-application syntax because it uses a different placeholder: it uses (?), not ?. This is similar to the <?> and {?} previously proposed by @ljharb in #91 (comment). But even ? itself can be used in Proposal 2 and 4 if syntactic-partial application is forbidden in Hack pipes’ RHSes (see #91 (comment)).

@littledan: IMO unless we want to argue that partial application isn't going to happen, we should try to make placeholders explainable as them.

@zenparsing: Then I think we ought to have that conversation, because the forward-compatibility constraint is leading towards a bizarre set of special-case rules that I don't think anyone wants or needs.

This question—to what extent the placeholder in Proposals 2, 3, and 4 should resemble syntactic partial application’s ? placeholder—is probably already covered by the bikeshedding in #91. As for placeholders in F-sharp Style Only, perhaps that would be covered by that new issue for Proposal 1b.

@ljharb
Copy link
Member

ljharb commented Feb 6, 2018

Why would x |> f(? + 1) be a SyntaxError? That seems very confusing.

@gilbert
Copy link
Collaborator Author

gilbert commented Feb 6, 2018

@ljharb Because ? is a full argument slot, rather than a variable with a value. This restriction prevents stuff like x |> f(? ?? ? ? : ?).

@js-choi You're right, if (?) were adopted, then there would be no need for the |> await special case. As you also mention, F-sharp plus (?) is the smart mix proposal. I suppose that might look something like this:

// Basic Usage
x |> f           //-->  f(x)
x |> f((?))      //-->  f(x)
x |> f(?)        //-->  Syntactic sugar?
x |> f((?) + 1)  //-->  f(x + 1)
x |> f(y)        //-->  f(y)(x)

// 2+ Arity Usage
x |> f((?),10)      //-->  f(x,10)
x |> f(?,10)        //-->  Syntactic sugar?
x |> f((?),10,(?))  //-->  Syntax error?

// Async Solution
x |> f |> await (?)       //-->  await f(x)
x |> await f((?))           //-->  await f(x)
x |> f |> await (?) |> g  //-->  g(await f(x))

// Arbitrary Expressions
f(x) |> (?).data          //-->  f(x).data
f(x) |> (?)['my-data']    //-->  f(x).data
f(x) |> { result: (?) }   //-->  { result: f(x) }

This seems pretty acceptable, aside from the requirement to write extra parens in
e.g. x |> f((?), 10). But maybe that's ok?

@ljharb
Copy link
Member

ljharb commented Feb 6, 2018

@gilbert restricting the usage to "once per pipeline entry" seems like it'd cover that?

@js-choi
Copy link
Collaborator

js-choi commented Feb 6, 2018

@gilbert: I must be misunderstanding something about this (?)-placeholder Smart Mix proposal. If bare ? is eventually used by syntactic partial application, then why would x |> f(?) not be equivalent to f(?)(x), f(x), and x |> f((?))? Ditto for x |> f(?, 10), which, as far as I can tell, would be equivalent to f(?, 10)(x) and f(x, 10) and x |> f((?), 10). And why would x |> f((?), 10, (?)) be a syntax error; why would it not be f(x, 10, x)? Thanks for your patience.

@mAAdhaTTah
Copy link
Collaborator

As for the first two options in #89 (comment), should they get their own issue, as a “Proposal 1b”?

I think it's close enough to being a type of "mix" that we can discuss it here.


Then I think we ought to have that conversation, because the forward-compatibility constraint is leading towards a bizarre set of special-case rules that I don't think anyone wants or needs.

If we want to keep open partial application's options for its choice of syntax as open as possible, that makes a decent case for F#-style, no placeholders, and defer placeholders to that proposal. I think this becomes more appealing if this syntactic change makes it feasible to write arrow functions without parens.

Otherwise, I think we should specify a goal in relation to the placeholders proposal before we bikeshed the token & mixes. If we use (?), what's the relationship between the placeholders proposals & how pipeline placeholders? Are they usable together, or are we expecting the placeholders proposal to supersede this?

@zenparsing
Copy link
Member

I don't think we want to pin special semantics to having anything wrapped in parenthesis.

@js-choi
Copy link
Collaborator

js-choi commented Feb 6, 2018

Forward compatibility with the ?-using partial-application syntax is not even a problem if the Hack-pipe placeholder is not also ?. Forward compatibility is a problem only insofar that the Hack-pipe placeholder must also be ? (or something resembling it, like (?))…and I am not sure that this resemblance is a very important goal. Its placeholder and Hack pipes’ placeholders serve two quite different purposes. In any case, the Hack-pipe placeholder’s name is just more bikeshedding for #91.

@mAAdhaTTah
Copy link
Collaborator

@js-choi The concern is we could end up with two different placeholder syntaxes, one within pipelines and one outside of them. @littledan suggested "we should try to make placeholders explainable as them." I'm hesitant to include a placeholder syntax at all because of this, but if we're going to, I do think we need to explicitly decide the relationship between the placeholder we're trying to ship with the pipeline and the placeholder proposal, even if that is to agree that we're willing to potentially ship 2 placeholder syntaxes (inside & outside of pipelines).

@js-choi
Copy link
Collaborator

js-choi commented Feb 6, 2018

@mAAdhaTTah: Making pipe placeholders explainable as partial-application placeholders is an understandable goal, but I don’t see how it’s possible at a fundamental level, as long as we’re talking about Hack-style pipes that support arbitrary expressions. Partial application cannot explain anything other than function calls (and method calls if the partial-application syntax will support them). It alone cannot explain arbitrary expressions such as arithmetic operators, instanceof, typeof, await, yield/yield *, etc. Even if they had been coupled in their initial proposals, these two things are quite different beasts.

After all, this still is a valid use case: to use partial application inside of a Hack pipe, such as … |> f.bind(null, ^^, 10) |> … or … |> f(^^, 10, ?) |> ….

(This is true even with tc39/proposal-partial-application#13; even if syntactic partial application adopted a prefix as in □ foo(?), then either ? must not be shared between syntactic partial application and pipelining or syntactic partial application must be forbidden in each pipe’s RHS—because, e.g., … |> □ f(?, 10, ?) would be ambiguous.)

@zenparsing
Copy link
Member

Yep, partial application is a red herring with respect to pipelines.

@mAAdhaTTah
Copy link
Collaborator

mAAdhaTTah commented Feb 6, 2018

Making pipe placeholders “explainable as” partial-application placeholders is an understandable goal, but I don’t see how it’s possible at a fundamental level, as long as we’re talking about Hack-style pipes that support arbitrary expressions.

I agree, but I see this as an argument for F#-style rather than dropping the forward-compatibility requirement. Perhaps something like |> f(^^, 10, ?) contains a lot of power but I fear that pushes over too far into the "ASCII soup" concern voiced in #75 (comment).

Which is not to suggest I'm opposed to the "Smart Mix", although I might reframe is as "Hack-style with inlinable unary function", which is to say x |> fnA |> await $ |> fnB($, 2) is valid, using whatever placeholder we decide to use. What I am suggesting is that we don't cripple the Hack-style proposal for the sake of forward compatibility if it's not feasible to achieve with the full power Hack-style provides, and explicitly decide that's the route we're going to take.

@littledan
Copy link
Member

@zenparsing

Yep, partial application is a red herring with respect to pipelines.

Could you explain what you mean here? Do you think partial application as @rbuckton proposed is a bad idea, or that it would be fine to have two separate tokens here, as they are doing different things?

@js-choi
Copy link
Collaborator

js-choi commented Feb 6, 2018

@mAAdhaTTah: I see this as an argument for F#-style rather than dropping the forward-compatibility requirement.

If that ambiguity (when making the partial-apply placeholder and pipe placeholder both ?) is an argument for Proposal 1: F-sharp Style Only…then that argument is strong only insofar that “making pipe placeholders explainable as partial-application placeholders” is a strong requirement. But is this requirement really such a desideratum? Non-function-call expressions such as method calls, arithmetic operators, instanceof, typeof, await, yield/yield *, etc.—would “making pipe placeholders explainable as partial-application placeholders” be worth making all of these other types of expressions into either ad-hoc special cases or simply not supporting them in pipelines at all?

Either way, the forward-compatibility requirement is moot; it’s covered by all four proposals. For Proposals 2, 3, and 4 it merely means that pipe placeholders can’t be the same as partial-apply placeholders.

And it seems to me that these two types of placeholders are fundamentally different concepts. Just look at f(?, 3, ?). This is a function with two parameters; when the function is called, the two ?s here may represent two different values. This is not at all similar to x |> f(^^, 3, ^^); there is but one parameter here with one value. Trying to explain pipelines (which are fundamentally unary) in terms of partial application (which is n-ary) seems to me to be a fundamental mismatch in their models.

@mAAdhaTTah: Perhaps something like |> f(^^, 10, ?) contains a lot of power but I fear that pushes over too far into the "ASCII soup" concern voiced in #75 (comment).

This particular ASCII soup is a result of mixing ^^ and ?. It is a problem only insofar that creating functions through partial application in a pipeline is frequent. And creating functions through partial application in a pipeline probably wouldn’t be frequent, much less so than something like await or ^^ + 1. But it’s still occasionally useful, and I think forbidding it would be much weirder.

And, hey, even if creating functions through partial application in a pipeline were super frequent, minimizing its visual noise would just be more bikeshedding for #91. We could always go Unicode, hahaha…oh, boy.

Also, hey, thanks for engaging so cordially on this. Just wanted to say that. 👍🏻

@kurtmilam
Copy link

@gilbert I'm referring to "Hack Style" only in that comment. I've stated elsewhere in this and other discussions that I support the Smart Mix and Split Mix proposals, although my current preference is for an F# solution (with room to grow in the future) in the operator's first iteration.

@mAAdhaTTah
Copy link
Collaborator

By itself the F-sharp operator works great for one use case and not much else.

I suspect there is significant overlap between expressions you can write with Hack-style pipes that would work the same if wrapped in an arrow function, and I don't think wrapping these with a familiar syntax is a heavy burden, although doing so is definitely noisier. Quite honestly, in the two examples @js-choi has above, the F#-style seems pretty reasonable, if less desirable.

That said, we should be able to bare this out with some real-world usage after we complete the babel plugins. I'm not a heavy user of async / await yet

...it feels like some of its advocates are coming up with some unsubstantial arguments for it.

This feels needlessly personal. Would you mind rewording?


@kurtmilam Advocating for F#-style and punting off the possibility of Hack-style pipeling to a future enhancement feels like shirking our responsibility to design this feature properly the first time. If you feel Hack-style pipelining is worth including, I think you should advocate for that now, rather than deferring that off to a future change / proposal.

@gilbert
Copy link
Collaborator Author

gilbert commented Feb 8, 2018

This is my intention, as well. It's absolutely not my intention to argue unfairly for my preferred solution

Let me say I never thought you or anyone has or had ill intention. Keeping things fair does not mean "looking out for bad guys", but just making sure things are played out properly. Just like a board game, someone might "cheat" by accidentally stepping over a rule if other players don't keep them in check.

The two claims of mine that you seem to take issue with, summarized, are...

These two claims have been qualified since their original introduction, and in their current form I agree with them.

@gilbert
Copy link
Collaborator Author

gilbert commented Feb 8, 2018

So I just discovered a new operator in JavaScript that works today! It's called $=

async function go (str) {
  let $;
  return (
    $= str,
    $= $ + $,
    $= $.toUpperCase(),
    $= Promise.resolve($),
    $= await $,
    $= log($),
    $= `oh ${$}`
  )
}
const log = (x) => { console.log(x); return x }

go("hi").then(log)
// "HIHI"
// "oh HIHI"

This is working code! We might not need the Hack-style operator after all 😛

@rbuckton
Copy link
Collaborator

rbuckton commented Feb 9, 2018

So I just discovered a new operator in JavaScript that works today! It's called $=

Except that your $ variable is highly polymorphic, and thus might not be very efficient in an optimizing compiler.

@js-choi
Copy link
Collaborator

js-choi commented Feb 10, 2018

@littledan: I’ve signed the contributor agreement and started a spec repository for a Proposal 4. Other than IRC Freenode #tc39, and maybe the es-discuss mailing list, is there a more informal place I could ask for questions on Ecmarkup and for general guidance on the spec drafting? For instance, I’m currently having trouble getting Ecmarkdown to be recognized in an emu-intro element. But I don’t want to clutter up this issue with lots of questions. Thanks!

@littledan
Copy link
Member

@js-choi Let's talk either on #tc39 or in issues here. Others might run into the same problems as you, so it's helpful to have an informal place.

I haven't tried using ecmarkdown in an emu-intro section before. I'm wondering, why are you putting grammar notation in an introduction? When I write introductions, I usually stick to plain text, maybe with some paragraphs, links, lists and code samples. I tend to put grammar in an emu-clause section. If you want to write an extended informal text to describe the approach to the solution, this could also be done in a separate Markdown explainer document.

As for not cluttering up this issue: Would it make sense for @js-choi and @mAAdhaTTah to each open up issues to track progress on their separate proposals? We can have more focused discussions there.

@js-choi
Copy link
Collaborator

js-choi commented Feb 10, 2018

@littledan: Talking on IRC #tc39; thanks for replying there. To answer your question above, I’m not trying to put Grammardown or other grammar notation in an emu-intro element: rather, I’m just trying to use Ecmarkdown for paragraphs. The introduction to Ecmarkup’s documentation suggests I should be able to use Ecmarkdown for “paragraphs”, at least, and I don’t see any documentation suggesting that emu-intro’s paragraphs are handled specially.

As for separate issues, I’m neutral, but it might be useful. Maybe it might be good to wait a bit until the specs and plugins are developed further. Once we continue developing the specs and plugins further, perhaps we’ll see how much discussion occurs around them. But I don’t know.

@mAAdhaTTah
Copy link
Collaborator

I'm starting with the babel plugin first, and I'll open an issue about it once it's ready.

@mAAdhaTTah
Copy link
Collaborator

Just a quick update, since things have quieted down here a bit: I stated working on |> await support, but since it doesn't currently parse (since await alone is not currently valid), it requires an update to babylon, which I'm still digging into.

@js-choi
Copy link
Collaborator

js-choi commented Feb 15, 2018

To add onto @mAAdhaTTah, us two have had professional work take up most of our time this past week, but we’ve also been able to put some work into the Babel plugins and formal specifications of our respective proposals (1: F-sharp Style Only and 4: Smart Mix) in our free time, while helping each other through email.

We have deliberately been working from opposite ends: @mAAdhaTTah has been working on Proposal 1’s Babel plugin first. I have been working on writing Proposal 4’s formal specification first. Many problems with Babel that @mAAdhaTTah will run into are problems that I would also run into—likewise, the problems I’d run into with the spec and with Ecmarkup would also apply to both of us.

So we figured it’d be most efficient to start work from the two opposite ends (plugin and specification), then adapt each other’s work for the half we haven’t worked on.

My own specification’s repository is public, as I mentioned in #89 (comment). Anyone is free to watch its progress, but it is still quite unfinished and rapidly churning.

I’ve mostly figured out how Ecmarkup works, but I have been churning out an explainer and a specification together in the Markdown readme first; the Ecmarkup document will come later. I hope to have my first presentable and well-rounded explainer+specification by the end of this week, but the planning fallacy will probably strike me, so it’ll hopefully only be a little bit later…

We’ll keep you posted later this week.

@js-choi
Copy link
Collaborator

js-choi commented Feb 22, 2018

An update after a week:
We’re still working on the problem from opposite ends.

The Babel plugin for Proposal 1 (F-sharp Only with … |> await |> …) has run into some parser complications. More specifically, Babylon the parser itself would have to be patched to handle any bare await lacking a following identifier (see #85 (comment)). @mAAdhaTTah is still working hard on it and we will hopefully have something to show in this space soon.

A first-draft formal specification for Proposal 4 (Smart Mix) has been finished and uploaded to my personal website. The draft is barebones but I think it completely specifies all the basics of Proposal 4 (Smart Mix).

In contrast, Proposal 4’s explainer is not yet ready; the explainer will take a few more days before it is presentable for first review. I want to completely remove the current middle section, which is both now out-of-date and redundant with the formal specification. I expect that many questions regarding the specification’s design will be answered by the finished explainer.

I also want to add more real-life examples from real-life libraries to the explainer. Right now it uses code from/with Underscore, Pify, and the WHATWG Streams standards, but I also want to add examples from/with Lodash, jQuery, Flux, Cycle, RxJS, and Ramda. If you have any other suggestions for important JavaScript libraries with which to show demonstrations (both from within their implementations or from code using their public APIs), please let me know.

I also still want to add some more brief informative comments to the specification and maybe even add tentative grammars for add-on proposals, like pipe functions (see issues #96 and #97), in an appendix of the specification.

After rewriting the explainer and adding more real-life examples, I plan to then either move onto Proposal 4’s Babel plugin, start a formal specification for Proposal 1, or start a formal specification for Proposal 3 (Split Mix).

I’ll leave another update when the situation changes further or after another week – whichever comes earliest. Thanks.

@js-choi
Copy link
Collaborator

js-choi commented Mar 8, 2018

Another update:

@mAAdhaTTah and I are still collaborating, mostly via email. He's been working hard on extending Babylon (the raw parser of Babel) to allow |> await. He has submitted a Babylon pull request at babel/babel#7458 with his work, which recently got approved from a reviewer. We’ve been having some conversations there about how to group the proposals in the Babel plugins (one plugin with configs or separate plugins).

We’ve both started to work on implementing the Babel plugin in the same repository.

I myself have finally finished a detailed explainer and specification for Proposal 4: Smart Pipelines, plus several possible extensions to it. @littledan will be able to look at it in a few days, and if he has time he will prepare a presentation presenting it and Proposal 1: F-sharp Style Only to the next TC39 meeting, later this month.

Thanks for all your patience.

@jlaustill
Copy link

@js-choi How would I go about helping out with these plugins and testing? I'm not really sure where/how to plug in.

@mAAdhaTTah
Copy link
Collaborator

@jlaustill Best bet to get started is to get familiar with the specs as they currently exist. Those are linked from the README in this repository.

Otherwise, I don't know as there is much you can do at this point. The next steps are to get the proposals in babel. We've landed some initial scaffolding so we can introduce new changes without introducing breaking changes.

We've got a PR here for babel: babel/babel#8289 That was mostly implemented by @js-choi, and I'm currently working on shepherding that into babel proper. We're mostly waiting on reviews from the babel team there, and I'm sure they're focused on getting babel@7 out the door, so that may take some time.

We're also waiting for that to land before I start the F# Pipeline parsing, then after that, the babel plugins themselves need to be implemented. Given the complexity of the Smart pipelines, I expect the rest of those pieces to move a bit faster.

Given that a lot of stuff is waiting for that initial PR to land, I'm not sure there's much you can do except tell people about the proposal as it stands. I've seen a lot of great input & conversation from the community, so any additional conversations / feedback would be appreciated.

Otherwise, hold tight! Things are in progress, even if it sometimes feels like nothing is happening.

@kurtmilam
Copy link

kurtmilam commented Sep 10, 2018

So I just discovered a new operator in JavaScript that works today! It's called $=

Except that your $ variable is highly polymorphic, and thus might not be very efficient in an optimizing compiler.

@rbuckton Would it not be relatively straightforward for the compiler to optimize away the polymorphy of $ in @gilbert 's example so you end up with something like this?

async function go (str) {
  return `oh ${log(await Promise.resolve((str + str).toUpperCase()))}`
}

@rbuckton
Copy link
Collaborator

Not exactly, since your "optimized" version doesn't execute in the same order as @gilbert's example. That said, an optimizing compiler could optimize this case, but that assumes it would happen often enough in user code that it would be worth optimizing.

@kurtmilam
Copy link

kurtmilam commented Sep 11, 2018

Did I make an error in the transformation? I haven't found it after double checking.

Regardless, the important point is that this kind of operation can be optimized. Thus, JavaScript has an existing operator that gets us very close to the functionality and syntax we'd expect from a Hack style pipeline operator.

If this doesn't happen often enough in user code already, given the existing operator, I wonder how much sense it makes to encumber a new pipeline operator with similar functionality.

@rbuckton
Copy link
Collaborator

Its the order of evaluation that differs. In @gilbert's example, the following steps are taken in order:

  1. Evaluate str.
  2. Evaluate $ + $.
  3. Evaluate $.toUpperCase
  4. Evaluate $.toUpperCase().
  5. Evaluate Promise.resolve.
  6. Evaluate Promise.resolve($).
  7. Evaluate await $.
  8. Evaluate log.
  9. Evaluate log($).
  10. Evaluate `oh ${$}`.

In your "optimized" version, the following steps are taken in a different order:

  1. Evaluate log.
  2. Evaluate Promise.resolve.
  3. Evaluate str.
  4. Evaluate str + str.
  5. Evaluate (str + str).toUpperCase.
  6. Evaluate (str + str).toUppercase().
  7. Evaluate Promise.resolve((str + str).toUppercase()).
  8. Evaluate await Promise.resolve((str + str).toUppercase()).
  9. Evaluate log(await Promise.resolve((str + str).toUppercase())).
  10. Evaluate `oh ${log(await Promise.resolve((str + str).toUppercase()))}`.

Differences in evaluation order can be observable due to side effects.

@kurtmilam
Copy link

Thanks for taking the time to spell out the differences in evaluation order between the two examples. I found that very informative.

It's also a concrete reminder (for me) of one advantage of minimizing / corralling side effects and mutation.

@tabatkins
Copy link
Collaborator

Closing this issue, as the proposal has advanced to stage 2 with Hack-style syntax.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 11, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests