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

Proposal: create a new function instead #284

Closed
JamesJansson opened this issue Jan 20, 2023 · 8 comments
Closed

Proposal: create a new function instead #284

JamesJansson opened this issue Jan 20, 2023 · 8 comments

Comments

@JamesJansson
Copy link

Given that pipes are a huge syntactical change, even after acceptance the syntax might not be confidently used for many years. On the other hand, creating a new function that accepts an initial value, then allows you call .next(functionName) and then (.end()) allows people to use it straightaway and allows polyfills to be used confidently until acceptance is broad.

Example:

const val = pipe(3)
  .next(add2)
  .next(square)
  .end();

I've got working code for pipe in this gist here, along with a crazy non-recommended version called pwhyp: https://gist.github.com/JamesJansson/923f60d0738a9cae1622947da66d4a0b

@maritaria
Copy link

I suspect that the way the . operator makes every method/function an object carries (or inherits from the proto-chain) an infix operator is so popular because of the way people's brain can read the code, especially when typing it. That is what |> changes for "plain" function calls as well, it replaces the nesting of function calls with a pipeline. The pipeline has a border on every |> where everything either side of the pipeline operator is a self-contained pipeline section.

@tinydogio-joshua
Copy link

I think they cover their reasoning about not doing this here: https://github.com/tc39/proposal-pipeline-operator#method-chaining-is-limited

@maxired
Copy link

maxired commented Jan 20, 2023

I second @JamesJansson on this.

@tinydogio-joshua I don't think this section does a great job at explaining why it would not works.

Also, let's not forget that promises already provides some chaining.

here is a potential implementation of the sample from the proposal Readme.

const chain = (el) => Promise.resolve(el);
chain(Object.keys(envars))
    .then(x => x.map(envar => `${envar}=${envars[envar]}`))
    .then(x => x.join(' '))
    .then(x => `$ ${x}`)
    .then(x => chalk.dim(x, 'node', args.join(' ')))
    .then(console.log)

I do agree that this is more verbose than this proposal, and maybe harder to reason in some cases, such as dealing with other promises, but at least I think this should be documented.

@tinydogio-joshua
Copy link

I'll leave that to those actively working on this. I just watch this repo as I'm excited for the feature. I figured I'd point out where they try to address this.

@ljharb
Copy link
Member

ljharb commented Jan 20, 2023

You can use syntax straight away with babel; that's not a good reason to ship API over syntax.

@tabatkins
Copy link
Collaborator

Using this style of chaining (this is just the trivial functor object) has all the downsides that already caused us to reject F#-style pipelining, and more besides. (See #206 and #221 for more discussion.)

@jjhiggz
Copy link

jjhiggz commented Jan 20, 2023

Here's an example where I think pipelines are objectively better
image
vs
image

I think that the power of the hackpipe here is that it allows us to have a lot more fine grained control of when we choose to pipe something. It's also worth acknowledging that Javascript already does a pretty awesome job with the . chain syntax but without pipeline operator there's never going to be a super smooth interop between . style chaining and pipe style chaining.

With the syntax proposed here I would start my function with

const sumCharCodes = (str: string) => 
      str
        .split("")
        .map(s => s.charCodeAt(0))
        

Then when I get to the sum part I'm either going to say to myself

"crap I probably should have started with a chain"

Or I'll say

"screw it let me just build a sum method inside of a reduce"

Now if I want to do this cleanly with good composition I need to refactor potentially many lines of code.

I totally agree there's a tradeoff here, but it's worth acknowledging the distinct benefits to a pipeline over something that we can just build with current js.

@Jopie64
Copy link

Jopie64 commented Jan 22, 2023

There's a separate proposal to (among some other functions) add Function.pipe. (Unfortunately it was rejected for now.)
But even without that, you can already use libs like Ramda to create such functions like sumCharCodes quite cleanly.

const sumCharCodes = R.pipe( 
        R.split(""),
        R.map(s => s.charCodeAt(0)),
        R.sum
);

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jan 30, 2023
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

8 participants