TC39/proposal-pipeline-operator Hack-style |> hijacks Grouping operator ( )
Tags: javascript, typescript, tc39, functional
Published: 2021-09-25 23:28:23







 [TC39 proposal  Hack Pipeline Operator](https://github.com/tc39/proposal-pipeline-operator) `|>` is incompatible with  [Grouping operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Grouping) `()`.

# Short version

### [Grouping operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Grouping)  `( )`

> The grouping operator  `( )`  controls the precedence of evaluation in expressions.

> The grouping operator consists of a pair of parentheses around an expression or sub-expression to override the normal operator precedence so that  **expressions with lower precedence can be evaluated before an expression with higher priority.**

### Test Code 1:

```
const f = a => a * 2;
const g = a => a + 1;

1 |> f(^) |> g(^);
1 |> (f(^) |> g(^));  
```
Now we made  `(f(^) |> g(^))`  to be evaluated before other expressions with higher priority.

I've investigated with Babel, and the transpiled result is identical, which means:
 `(f(^) |> g(^))`   is NOT evaluated before other expressions with the rule of Grouping operator `( )`.

![image](https://user-images.githubusercontent.com/1316994/134595674-9a280ced-0fb3-4c04-ac91-9fd84e483404.png)

**Does the current proposal  Hack `|>` hijack the  [Grouping operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Grouping)  ?**

### Test Code 2:

Now I have a `log` function.
    
    
    const right = a => b => b;
    const log = a => right(console.log(a))(a);

This behaves like identity function: `a => a` which does not affect to the original code but `console.log(a)` in the process.

Now, we want to know the evaluated value of `(f(%) |> g(%))`

    1 |> (log(f(%) |> g(%)));

This should be totally fine because `(f(%) |> g(%))` must have some value of the evaluation according to:

>The grouping operator consists of a pair of parentheses around an expression or sub-expression to override the normal operator precedence so that **expressions with lower precedence can be evaluated before an expression with higher priority.**



![File:Some babel code.jpg](https://upload.wikimedia.org/wikipedia/commons/5/54/Some_babel_code.jpg)

The vanilla JS code is:

    var _ref, _ref2, _ref3, _ref4;
    const id = a => a;
    const right = a => b => b;
    const log = a => right(console.log(a))(a);
    const f = a => a * 2;
    const g = a => a + 1;
    _ref2 = 1, (_ref = f(_ref2), g(_ref));
    _ref4 = 1, log((_ref3 = f(_ref4), g(_ref3)));

and the result is:
`3`

Therefore,

    1 |> (f(%) |> g(%));

where  `(f(%) |> g(%))` == `3`

`1 |> (f(%) |> g(%))` 
 `==`
`1 |> 3`

**???**

and the evaluation value of whole `1 |> (f(%) |> g(%))`  is `3`
therefore,
`1 |> 3 == 3`

I have no idea for this hack-pipe-operator, and simply think this has broken the laws of Mathematics, and more importantly, it seems **the current proposal  Hack `|>` hijacks the  [Grouping operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Grouping)**

### The Babel implementation

https://github.com/tc39/proposal-pipeline-operator/issues/227#issuecomment-926136875

>The Babel implementation has been done by [@js-choi](https://github.com/js-choi) (one of the champions of the Hack pipes proposal).  
The "reasonable stardard" is the spec proposal: either you learn how to read it (I'd be happy to help, if you are confused about any spec part), or you trust what who can read it says.

### Issue
In fact, I made an issue for this.

**Does the current proposal override the Grouping operator ( ) with Hack |> ?  #229**
https://github.com/tc39/proposal-pipeline-operator/issues/229
![image](https://user-images.githubusercontent.com/1316994/134628159-8c1f10ec-e6c9-4a7a-b0bd-9c0948de65cf.png)

https://github.com/tc39/proposal-pipeline-operator/issues/229#issuecomment-926308352
>As had been explained already, parentheses don't work the way you seen to think they do. The result you're getting from Babel is entirely correct and expected, with exactly the same precedence and execution order that you'd get from parenthesizing a sequence of additions.

>As this question has been answered, I'm closing this thread.

![File:Tc39 terms.jpg](https://upload.wikimedia.org/wikipedia/commons/4/43/Tc39_terms.jpg)

Issue closed with the tag of **invalid**, well, I don't think so.

@js-choi has explained to me for sure:

https://github.com/tc39/proposal-pipeline-operator/issues/227#issuecomment-926317660

@js-choi explanation
---

Hm. Well…I don’t think anyone is admitting or covering anything up. But I’ll give it a shot; hopefully this will help a little. ^_^

Parentheses change grouping. But they never have changed evaluation order, which is  _always_  left to right, even  _outside_  of parentheses. This is how JavaScript (and many other programming languages) have always been:

    function f () {
      console.log('F');
      return 3;
    }
    
    function g (x) {
      console.log('G');
      return x + 4;
    }
    
    function h (x) {
      console.log('H');
      return x * 7;
    }
    
    // This will print F then G then H, and it will result in 3 * 12, i.e., 36.
    `f() * (g(1) + h(1))`

Note how the  `f()`  evaluates first even before  `(g(1) + h(1))`, despite  `(g(1) + h(1))`  being in parentheses. That’s why F still prints first before G and H.

Parenthesized expressions are not always evaluated first; expressions outside of the parentheses to the left are evaluated beforehand. This has how JavaScript (and many other languages like C and Lisp) have always been.

Parentheses change grouping. But they have  _never_  changed evaluation order, which is  _always_  left to right, even  _outside_  of parentheses. This is how JavaScript (and many other programming languages) have  _always_  been:

    // f, g, and h have the same definitions above.
    
    // This will print F then G then H, and it will result in 3 * 12, i.e., 36.
    f() * (g(1) + h(1))
    
    // This will also print F then G then H, and it will result in 7 * 7, i.e., 49.
    f() |> (g(^) |> h(^))

Note how the  `f()`  evaluates first even before  `(g(1) + h(1))`, despite  `(g(1) + h(1))`  being in parentheses. That’s why F still prints first before G and H.

This is the same reason why  `f() |> (g(^) |> h(^))`  causes  `f()`  to be evaluated before  `(g(^) |> h(^))`.

Just like how  `f() * (g(1) + h(1))`  causes  `f()`  to be evaluated before  `(g(1) + h(1))`.

It’s just the  _old_  left-to-right evaluation rules. There aren’t any special grouping rules here. Parentheses change the grouping, but they  _never_  have changed execution order from anything other than left to right.

Hopefully that clears it up a little! I can understand why it might be a little confusing, but it’s just the old rules. Nothing is happening here except for the old JavaScript evaluation/parentheses rules. ^_^

(Actually, perhaps I should also edit MDN’s documentation to make this clearer. Maybe this old parenthesized-expressions-are-not-always-evaluated-first rule is tripping up many people learning JavaScript.)

My explanation
---


[#227 (comment)](https://github.com/tc39/proposal-pipeline-operator/issues/227#issuecomment-926270855)  [@jridgewell](https://github.com/jridgewell)

>Notice the order "two", "three", "four" isn't affected by the parenthesis. Let's try (two() * three()) + four(). Surprise, it's still "two", "three", "four"! But now the final log is 10. That's because the operands are evaluated left to right, and this doesn't change. What changed was the evaluation of the operators.

[#227 (comment)](https://github.com/tc39/proposal-pipeline-operator/issues/227#issuecomment-926317660)  [@js-choi](https://github.com/js-choi)

>Note how the f() evaluates first even before (g(1) + h(1)), despite (g(1) + h(1)) being in parentheses. That’s why F still prints first before G and H.

I observe, again, two of you share the same concept, and there are confusion of concepts . So I will explain to you. Hope it helps, really.

### Confusion of concepts

The problem you illustrated is not for inconsistency or limitation of the functionality of the Grouping operator  `( )`  but [evaluation strategy](https://en.wikipedia.org/wiki/Evaluation_strategy) of JS that is [eager-evaluation](https://en.wikipedia.org/wiki/Evaluation_strategy#Eager_evaluation), in this evaluation strategy, `f(x)` is evaluated as soon as it is found from left to right, yes, you are only correct here.

The only "safe" place is right side of lambda expressions: such as `a => f(a)`. In this case, even it's found by compiler `f(a)` is safe! will not be evaluated. (the same goes to function statement). Therefore the technique is used to emulate lazy-evaluation. Another exception is `true || f(x)` but `false || f(x)` will be evaluated once found. Try it.

Then point is, what you told us is **nothing to do with the evaluation order of binary operator or Grouping operator `( )`**.

**The eager evaluation strategy strictly follows the Algebraic rule.** Well, if you can find anomaly, show me :) **It follows the rule of operators including Grouping operator () with no exceptions.** The eager evaluation of `f(x)` never harms Algebraic expression in JS. If both of you have explained as if eager evaluation of `f(x)` is the limit of the math in JS. That is the harmful explanation for us.

Sure in your code, we will have F G H or two three four order and so what? Does it break the rule of the math or algebraic structure? Nah..

>Parentheses change grouping. But they never have changed evaluation order, which is always left to right, even outside of parentheses. This is how JavaScript (and many other programming languages) have always been:

So, this is a false statement.

The tricky word is: evaluation **"order"**.

>Note how the `f()` evaluates first even before `(g(1) + h(1))`

So another tricky term should be : **"before"** or **"after"**

**In mathematics, when we use the term "order" "before" "after", does it mean time series? No way.** 

Does it mean the order of the line of terminal console?

This logs:

"two"

"three"

"four"

14

**Doesn't matter in terms of math structure.**

What does matter is [dependency network](https://en.wikipedia.org/wiki/Dependency_network) structure.

Binary operation is merely a syntax-sugar of binary function, and when you chain them, you fundamentally compose the functions.

![image](https://lh5.googleusercontent.com/Ezak8AuE-a_wm92oraHwb5YNxTOXM0mMCaINgELAS6KNRAd9vSOFub1-hTrnWLC-tBKKutHTQOfzDX1KHQgrUURzjuUDVjvYqnN9SCW4uaJecGTDMydystqnrJGIeFml_z3sJNEE=s0)

For instance, when you enjoy + binary operation, you guys repeatedly told me "left to right", but fundamentally you do

![image](https://lh5.googleusercontent.com/ePh4ZCounDhhlLkx5sKhrOyeiAeeJHUTqDmKm7kAM_1Xvh03hm9hwYgKFAU37gjreDGqpogGayfmFWGVOUVM_kmGA5TOiLiDW-j5tg9ZIM9EZPniKSIcnDqwOae2jsiMwY-tPPWz=s0)

This is Fold

[https://en.wikipedia.org/wiki/Fold_(higher-order_function)](https://en.wikipedia.org/wiki/Fold_(higher-order_function))

There are both left and right side fold, and usually we use foldLeft and if it's monoid the result is the same of both side.

As you seen, this is a Graph. [Dependency graph](https://en.wikipedia.org/wiki/Dependency_graph)

>In mathematics, computer science and digital electronics, a dependency graph is a directed graph representing dependencies of several objects towards each other. It is possible to derive an **evaluation order** or the absence of an **evaluation order** that respects the given dependencies from the dependency graph.

**Remember "evaluation order" derived from the dependency graph or structure is completely different concept of "time order" of executions.**

### Hack pipe

Hack pipe, on the other hand, unlike eager evaluation strategy, this does break the math structure, and again this one overrides Grouping Operator ( ). I meant in dependency base. This problem is elaborated in my previous post [#227 (comment)](https://github.com/tc39/proposal-pipeline-operator/issues/227#issuecomment-926371664)

I don't think it's on purpose, but the confusion of concept of Evaluation strategy and Algebraic structure is harmfully explained to justify the false design of Hack pipe that overrides the operator with the highest precedence in JS.

I will maintain my claim:

[Does the current proposal override the Grouping operator ( ) with Hack |> ?](https://github.com/tc39/proposal-pipeline-operator/issues/229)  [#229](https://github.com/tc39/proposal-pipeline-operator/issues/229)

## Deletion of my explanation

@js-choi
>It’s just the  _old_  left-to-right evaluation rules. There aren’t any special grouping rules here. Parentheses change the grouping, but they  _never_  have changed execution order from anything other than left to right.

So this is a false statement.

So why there's no link to my explanation? Deleted by them.

![File:Delete comments.jpg](https://upload.wikimedia.org/wikipedia/commons/9/99/Delete_comments.jpg)

https://github.com/tc39/proposal-pipeline-operator/issues/227#issuecomment-926737650
>I have just deleted several comments from [@stken2050](https://github.com/stken2050) (and a few responses to them from others) that were explicitly continuing the confused argument about parentheses that I said just a few hours ago to _not_ continue. I'm closing and locking this thread, and pursuing separate moderation actions, as I said I would if this behavior continued.

Ok.
> **that were explicitly continuing the confused argument about parentheses that I said just a few hours ago to _not_ continue.** 

**So individuals who are confused are not me but the members to promote this Hack proposal, and they believe they have a power to tell which argument is to be allowed to continue or not. In other words, this is an abuse of power or Censorship to justify their own proposal for their own interest to achieve the standardization of this false Hacked product.**

Sure, I claimed to TC39, and I've got a mail from an individual on behalf of TC39 Chairs & CoC Committee:
https://gist.github.com/stken2050/5eff7d2a792cd2b9e773b09c64fd26da

Therefore, I understand TC39 has justified their abuse of power of censorship, and Banned me for 2 weeks.

**EDIT (2021/9/28):**
Now they added a false statement to the MDN page of  [Grouping operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Grouping) `( )`, for the purpose of justifying their own proposal that is based on the confusion of the concept:  **"evaluation order" derived from the dependency graph or structure is completely different concept of "time order" of executions.**

Please confirm here:
[Description confusing concepts clarified  #9389](https://github.com/mdn/content/pull/9389)

----
The point of view here has been shared in [stack overflow question](https://stackoverflow.com/questions/69384610/does-the-functionality-of-grouping-operator-in-javascript-differ-from-haske/69386130) , and [a third person confirmed the fact as the answer](https://stackoverflow.com/a/69386130/11316608
):

>Grouping parentheses mean the same thing in Haskell as they do in high school mathematics. They group a sub-expression into a single term. This is also what they mean in Javascript and most other programming language,

>A language needs other rules beyond just the grouping of sub-expressions to pin down evaluation order (if it wants to specify the order), whether it's strict or lazy. So since you need other rules to determine it anyway, **it is best (in my opinion) to think of evaluation order as a totally separate concept than grouping.** **Mixing them up seems like a shortcut when you're learning high school mathematics, but it's just a handicap in more general settings.**

Therefore, for the explanation of Grouping operator (parentheses) itself, the priority of the article should be to focus the functionality given as the meaning of  "high school mathematics".

The wording of old version "operands" of "preserved" actively misleads readers to confuse the  "high school mathematics" principle of the Grouping operator and the evaluation strategy of JavaScript runtime. 
 
If anyone think such an example is required and to be included in this page, they need to explain thoroughly for readers to avoid the confusion of concepts between the mathematical aspect and evaluation strategy that the latter is essentially off-topic here.

---

#### Reference material

[Does the functionality of Grouping operator () in JavaScript differ from Haskell or other programming languages?](https://dev.to/stken2050/does-the-functionality-of-grouping-operator-in-javascript-differ-from-haskell-or-other-programming-languages-1f20)

https://stackoverflow.com/a/69386130/11316608

----


# Long version

## What is grouping-operator?
### [Grouping operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Grouping) `( )`
>The grouping operator `( )` controls the precedence of evaluation in expressions.

>The grouping operator consists of a pair of parentheses around an expression or sub-expression to override the normal operator precedence so that **expressions with lower precedence can be evaluated before an expression with higher priority.** 

**Grouping operator `( )` itself has the highest precedence in JavaScript.**

### [Operator precedence](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence)

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gpp67pkm1nrx41ej85ba.png)
 
## What is pipeline-operator?

In a general sense, pipeline-operator `|>` is a [binary operator](https://en.wikipedia.org/wiki/Binary_operation)  for  [function application](https://en.wikipedia.org/wiki/Function_application) that is  equivalent to  `f(x)` 

`f(x)` == `x |> f`

## Benefit of binary operator

Introducing a new binary-operator in JavaScript is nothing new.

 In ES2016,  [exponentiation operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation) `**` has been introduced. 
`Math.pow(2, 3)` == `2 ** 3` 
`Math.pow(Math.pow(2, 3), 5)` == `2 ** 3 ** 5`

As you can see, a binary operator significantly improve the readability of a code, especially for the nesting structure of `f()` [notation](https://en.wikipedia.org/wiki/Mathematical_notation),

Essentially, pipeline-operator is the same league of the exponentiation operator, and the benefit is also common.

`g(f(x)` == `x |> f |> g`

## Expectation of the community

In fact, pipeline-operator in JS has been expected from the community.

[#StateOfJS 2020: What do you feel is currently missing from JavaScript?](https://2020.stateofjs.com/en-US/opinions/missing_from_js) 

![image](https://user-images.githubusercontent.com/1316994/133777701-55ffaa00-bede-4699-a907-fe85242ab82b.png)

-   Static Typing
-   Pattern Matching
-   Pipe Operator
-   functions
-   Immutable Data Structure

It's reasonable to observe that the majority of the JS community has longed for more strictness of the language.

Especially for  **Static Typing**:

![image](https://user-images.githubusercontent.com/1316994/134413770-55b00540-bde7-4b5c-ac84-9bbfa5a1371c.png)

## Why Static Typing is so popular?

There is no native static [type system](https://en.wikipedia.org/wiki/Type_system) in JavaScript, so currently, many use TypeScript instead.
So why do we like Type so much?

The general answer would be that we can avoid BUGs, in other words Type makes a code robust.

## Why Type makes a code robust?

Because Type is mathematics.
I will explain briefly about Type since I think the understanding helps readers follow this discussion.

## Types as Sets

Type == Sets

### [Type theory versus set theory](https://ncatlab.org/nlab/show/type+theory#type_theory_versus_set_theory)

>Alternately, we could change our terminology so that what we have been calling “types” are instead called “sets”.
>
>Thus, words like “type” and “set” and “class” are really quite fungible. This sort of level-switch is especially important when we want to study the mathematics _of_ type theory,

[](https://guide.elm-lang.org/appendix/types_as_sets.html)

### [Types as Sets · An Introduction to Elm](https://guide.elm-lang.org/appendix/types_as_sets.html)

>In pursuit of this goal, I have found it helpful to understand the relationship between types and sets. It sounds like a stretch, but it really helps develop your mindset!

## What is Sets?

### Definition of Function
https://en.wikipedia.org/wiki/Function_(mathematics)#Definition

>Intuitively, a function is a process that associates each element of a set _X_, to a single element of a set _Y_.

https://ncatlab.org/nlab/show/function

>In a strict sense of the term, a **function** is a [homomorphism](https://ncatlab.org/nlab/show/homomorphism)  f:S→Tf : S \to T of [sets](https://ncatlab.org/nlab/show/sets). We may also speak of a **[map](https://ncatlab.org/nlab/show/map)** or **mapping**, but those terms are used in other ways in other contexts.

So, in the definition of function, we need to define the sets of `x` and `y`
where `y = f(x)`, or  `x |> y`

## A binary operator is a syntax-sugar of binary functions

[Binary operation](https://en.wikipedia.org/wiki/Binary_operation)

![](https://upload.wikimedia.org/wikipedia/commons/thumb/7/79/Binary_operations_as_black_box.svg/220px-Binary_operations_as_black_box.svg.png)

As you can see in the picture,
`x * y == f(x, y)`

or should I edit this picture to

![File:Pipeline operator.png](https://upload.wikimedia.org/wikipedia/commons/2/23/Pipeline_operator.png)

A binary operator is a syntax-sugar of binary functions.
We also need to type (== sets) `x` and `y` or  `f` correctly as the request from the mathematical definition of function, and according to the overwhelming popularity of **Static Typing** in the survey, that is what people want. They needs more strictness of JavaScript for their robust codes.

For `x |> f === f(x)`, essentially it's clearly typed:

x : JavaScript Objects
f : Function

Then, since this is `f(x)`,  the type(==sets) of `x` should be defined along with the definition of `f`.

This is what people want.

## Hack-style reached Stage-2

Recently, I have noticed JS pipeline-operator has reached TC-39 Stage-2, so I have examined:
 [tc39](https://github.com/tc39)/**[proposal-pipeline-operator](https://github.com/tc39/proposal-pipeline-operator)**
 
------

### Pipe Operator (`|>`) for JavaScript

#### Why the Hack pipe operator

There were  **two competing proposals**  for the pipe operator: Hack pipes and F# pipes. (Before that, there  **was**  a  [third proposal for a “smart mix” of the first two proposals](https://github.com/js-choi/proposal-smart-pipelines/), but it has been withdrawn, since its syntax is strictly a superset of one of the proposals’.)

The two pipe proposals just differ  **slightly**  on what the “magic” is, when we spell our code when using  `|>`.

#### This proposal: Hack pipes

In the  **Hack language**’s pipe syntax, the righthand side of the pipe is an  **expression**  containing a special  **placeholder**, which is evaluated with the placeholder bound to the result of evaluating the lefthand side's expression. That is, we write  `value |> one(^) |> two(^) |> three(^)`  to pipe  `value`  through the three functions.

**Pro:**  The righthand side can be  **any expression**, and the placeholder can go anywhere any normal variable identifier could go, so we can pipe to any code we want  **without any special rules**:

-   `value |> foo(^)`  for unary function calls,
-   `value |> foo(1, ^)`  for n-ary function calls,
-   `value |> ^.foo()`  for method calls,
-   `value |> ^ + 1`  for arithmetic,
-   `value |> [^, 0]`  for array literals,
-   `value |> {foo: ^}`  for object literals,
-   ``value |> `${^}` ``  for template literals,
-   `value |> new Foo(^)`  for constructing objects,
-   `value |> await ^`  for awaiting promises,
-   `value |> (yield ^)`  for yielding generator values,
-   `value |> import(^)`  for calling function-like keywords,
-   etc.

------

**What??** 
I had a hope for `value |> f` is still valid, but syntax-error.

The type of right hand side of  `|>` is no longer function but **something unknown**.

## Reactions

I investigated the issue of this proposal.

-   #200: Added value of hack-style proposal against temporary variables  
    [https://github.com/tc39/proposal-pipeline-operator/issues/200](https://github.com/tc39/proposal-pipeline-operator/issues/200)
-   #202: Separate (complementary) F# pipeline proposal?  
    [https://github.com/tc39/proposal-pipeline-operator/issues/202](https://github.com/tc39/proposal-pipeline-operator/issues/202)
-   #205: Hack is dead. Long live F#.  
    [https://github.com/tc39/proposal-pipeline-operator/issues/205](https://github.com/tc39/proposal-pipeline-operator/issues/205)
-   #206: Should enabling point-free programming/APIs be a goal of the Pipeline Operator?  
    [https://github.com/tc39/proposal-pipeline-operator/issues/206](https://github.com/tc39/proposal-pipeline-operator/issues/206)

In fact, [#205: Hack is dead. Long live F#.](https://github.com/tc39/proposal-pipeline-operator/issues/205)  has 199 comments and now closed by moderator.
https://github.com/tc39/proposal-pipeline-operator/issues/205#issuecomment-918717394

This is a huge thread and reading there, I've watched the issue was closed in real-time.

Here are few comments I've found around threads:

[#205 (comment)](https://github.com/tc39/proposal-pipeline-operator/issues/205#issuecomment-918366356)  [@jderochervlk](https://github.com/jderochervlk)

> > The future of functional programming is Hack pipe

> Nope. It isn't. If this is truly what became added to the language I would continue to use Ramda's  `pipe`, which is a shame because I would really love to remove some overhead of installing a package in order to do something so simple.

[#205 (comment)](https://github.com/tc39/proposal-pipeline-operator/issues/205#issuecomment-918578339)  [@samhh](https://github.com/samhh)

> I'm thinking ahead. JavaScript won't cease to exist once Hack reaches stage 4.

[#215 (comment)](https://github.com/tc39/proposal-pipeline-operator/issues/215#issuecomment-923161293)  [@arendjr](https://github.com/arendjr)

> I would rather have the language remain without any pipe operator than to have to deal with Hack in the future.  
> I too would like to thank  [@js-choi](https://github.com/js-choi)  and the other contributors for all their effort, but I believe the current direction to be misguided to the detriment of not just the FP community, but the JS community at large.

[#225 (comment)](https://github.com/tc39/proposal-pipeline-operator/issues/225#issuecomment-924508816)  [@voronoipotato](https://github.com/voronoipotato)

> The argument against hack pipes is that we believe they are a hazard (sometimes for different reasons, but the conclusion is the same). Most of us in this thread and I suspect in the wild, would rather have no pipes, than hack pipes.

[#225 (comment)](https://github.com/tc39/proposal-pipeline-operator/issues/225#issuecomment-922983854)  [@SRachamim](https://github.com/SRachamim)

> PFA proposal is a universal solution to those who worries about the arrow function noise on all three cases: map, then and pipe. If PFA is not ready, and we don't want minimal/F# without PFA, then let's wait, instead of introducing an irreversible Hack pipes.

[#225 (comment)](https://github.com/tc39/proposal-pipeline-operator/issues/225#issuecomment-923003812)  [@SRachamim](https://github.com/SRachamim)

> And as I said, if PFA is stuck, then it's not a good reason to introduce Hack. We should either wait, or avoid pipe at all (or introduce minimal/f# style anyway).

[#225 (comment)](https://github.com/tc39/proposal-pipeline-operator/issues/225#issuecomment-924261193)  [@Lokua](https://github.com/Lokua)

> Also, as a writer whose job is to communicate meaning, hack style removes my ability to provide descriptive names, which is basically the universal first step of writing readable code. I'm honestly shocked at this proposal. Imagine if you started at a new company and they enforced that all unary functions you write regardless of context had to name their single argument  `x`  (or god forbid,  `^`  ![:trollface:](https://github.githubassets.com/images/icons/emoji/trollface.png ":trollface:")). That's how I feel and I'm not exaggerating - this proposal scares me because it's going to lead to code that is uglier, harder to read, and harder to refactor/abstract later on!  
> Edit: I too would rather see no pipe than this and am admittedly biased as I've always thought a pipe operator (or pretty much any more new syntax) is a bad idea. But if we are going to have it, I'd rather see it implemented in a way that improves readability, not (IMHO) hinders it.

I've found they claim it's far better not to have any pipe than to have hack-style because they evaluated the one harmful to JavaScript.

This is a comment by RxJS auhthor
https://github.com/tc39/proposal-pipeline-operator/issues/228#issuecomment-925465598
>I've been told several influential members want to discourage point-free programming. Therefore, anything that might help functional programming libraries is unlikely to pass the TC39. It is what it is. It's the hack proposal or nothing. IMO, the hack proposal isn't useful enough to justify the additional syntax. But I'm not on the committee

>Please don't @ me into these threads. I've said my piece. Pretty thoroughly. I wasn't really heard. And I lost a friend over it. I simply just don't care what happens with this anymore. If it passes, great. Unfortunately, I don't really have any use for the proposed pipeline operator. But I'm hopeful for other features someday that I will have a use for.

## History of the proposal

I think it's fair to share the history posted by a project member @js-choi

[Brief history of the JavaScript pipe operator](https://github.com/tc39/proposal-pipeline-operator/blob/main/HISTORY.md)



## My study on Hack

In fact, I had to study the Hack-style-pipeline-operator.
I had no idea what this is.
**For the minimal/F# proposal, it's merely `x |> f === f(x)` , so simple, no requirement to study.**

I had joined issues, and also I've opened a couple of issues by myself, and actually lots of text here is copy&paste of my own comment there.

## Pipeline-operator in a mathematical sense

Before I discuss Hack pipe, I share my knowledge on the pipeline-operator in a mathematical sense that is 
`x |> f === f(x)`

## Associative property and Monoid

**Addition**  
[https://en.wikipedia.org/wiki/Addition#General_theory](https://en.wikipedia.org/wiki/Addition#General_theory)

> General theory  
> The general theory of abstract algebra allows an "addition" operation to be any  **associative**  and commutative operation on a set. Basic algebraic structures with such an addition operation include commutative  **monoids**  and abelian groups.

Here the important property is associative

```
(1 + 2) + 3 = 
1 + 2 + 3 = 
1 + (2 + 3)
```

JS String is also has associative property, and they are called [Monoid](https://en.wikipedia.org/wiki/Monoid) in algebra.

> In abstract algebra, a branch of mathematics, a **monoid** is a set equipped with **an associative binary operation** and an identity element.
> 
> **Associativity**  
> For all a, b and c in S, the equation  `(a • b) • c = a • (b • c)`  holds.
>
> In computer science and computer programming, the set of strings built from a given set of characters is a free monoid.

What does this mean?

```
"Hello" + " " + "operator" ==
"Hello " + "operator" ==
"Hello" + " operator" ==
"Hello operator"
```

Strings and  `+`  the binary operator in JS is a Monoid, and as you know this String operator is very easy to use and robust.

Monoid or associative property has rock solid structure because it's hardly broken.  
**Imagine LEGO block, that is also Monoid, the order to construct block does not effect the result:**

```
(A + B) + C = 
A + B + C = 
A + (B + C)
```

Any order to construction of the combination of LEGO bock reaches the identical result. So in software development if the entity has Monoid property, we can treat it as if LEGO block. That's the virtue of Monoid. Just its like LEGO, wonderful stuff.

**Without the associative property, we will experience [Combinatorial explosion](https://en.wikipedia.org/wiki/Combinatorial_explosion)**.

>In [mathematics](https://en.wikipedia.org/wiki/Mathematics "Mathematics"), a **combinatorial explosion** is the rapid growth of the complexity of a problem due to how the [combinatorics](https://en.wikipedia.org/wiki/Combinatorics "Combinatorics") of the problem is affected by the input, constraints, and bounds of the problem.

**The history of software development is the war against complexity.**

**In fact, Associativity is one of the most important concept in programming and Associativity is the key to avoid the software complexity that is the fundamental reason of BUGs . In other words, as long as we are very carful to keep things with associative property, we safely can avoid complexity and obtain a bug-free code.**

So Associativity is important,  [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation)
![image](https://user-images.githubusercontent.com/1316994/134622162-0126479a-8741-4440-a431-f3b050c5a650.png)

They care a lot.

## Function composition as a Monoid

[https://en.wikipedia.org/wiki/Monoid](https://en.wikipedia.org/wiki/Monoid)

>For example, **the functions from a set into itself form a monoid with respect to function composition**.

I will explain this.

One of "the functions from a set into itself" is addition.

    // function from a set into itself
    const f = a => a + 1; // f: number -> number 
    const g = a => a + 2; // g; number -> number 

![image](https://user-images.githubusercontent.com/1316994/133987130-1d809aac-b322-4964-975e-865cf8c946e9.png)
![image](https://user-images.githubusercontent.com/1316994/133987268-d4ca147e-71ac-4e18-9567-e213dae96fcf.png)


![image](https://user-images.githubusercontent.com/1316994/134622508-49c2a242-f4ae-42d8-84a1-3332cb6c999a.png)


 ![image](https://user-images.githubusercontent.com/1316994/134622390-c397558b-36a6-45a4-a026-e9202e88f13c.png) 

-   please note I use the composition operator for g(f(x)) not  `g.f`  but  `f.g`

```
a |> f |> g   ===
a |> (f . g) 
```
This is the simple structure of
Function application (pipeline-operator)
Function composition (composition-operator).

They are the both side of the same coin.

![image](https://user-images.githubusercontent.com/1316994/134622406-9d78fb22-9bea-4e28-bc8a-b87f6e6637a4.png)

`(f.g).h === f.g.h === f.(g.h)`

Therefore, **function composition is Monoid**.


```
a |> f |> g |> h ===
a |> f |> (g . h) ===
a |> f . (g . h) ===
a |> (f . g) |> h ===
a |> (f . g) . h ===
a |> (f . g . h) 
```
where  `f.g`  is the composition of  `f`  and  `g`  
(in traditional math style is  `g.f`  regarding  `g(f)`  but I don't use this style )


This is the whole picture you should know, and as you can see:  
**function application  `|>`  is not associative and not Monoid.**

```
a |> f |> g   !=
a |> (f |> g) 
```
**The `(f |> g)`  does not make sense and the Type==Sets is violated in terms of `x |> f`**.

However, this is what the Hack style is doing. 

```
const f = a => a * 2;
const g = a => a + 1;

1 |> f(^) |> g(^);    //3
1 |> (f(^) |> g(^));  //3
```
and `(f(^) |> g(^))` is also evaluated as `3`,
 with the higher priority of general rule of Mathematics or grouping-operator `()`

as a result

`1 |> 3 == 3`

**This does not make sense at all, and the fundamental reason is they simply violates the rule of mathematics.**

## Monad

Pipeline-operator  `|>`  and function application does not have associative property in Monoid layer, but the  form 
```
a |> f |> g   ===
a |> (f . g) 
```
is also called Associativity in Monad layer.

[https://wiki.haskell.org/Monad_laws](https://wiki.haskell.org/Monad_laws)  

**Monad laws**
![image](https://user-images.githubusercontent.com/1316994/134077688-3eef39bf-52ea-48ca-b569-dac3910af75b.png)

For your convenience, I would rewrite to  
**Associativity:**  `(m |> g ) |> h === m |> (x => g(x) |> h)`
or 
**Associativity:**  `(m |> g ) |> h === m |> (x => x |> g |> h)`
as  `(x => x |> g |> h)`  is the function composition of  `g`  and  `h`
**Associativity:**  `(m |> g ) |> h === m |> (g . h)`

For **left-right identity**,

![image](https://user-images.githubusercontent.com/1316994/134623182-32783f14-876b-4ecb-a6ee-abc3d9f32ad9.png) 

with identify function:  `id= x => x` 
For every Function:  `f: A ->B`
If this forms, the algebraic structure is called **Monad**.
*Note: this corresponds to Monoid has associativity and identify*.

- **Function Application  `|>`  Monad**  
- **Function Composition  `.`  Monoid also Monad (obvious, but prove by yourself)**

So mathematically,  **`|>`  is Monad, not Monoid**.

FYI, 
[Array.prototype.flatMap()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap) introduced in ES2019
https://github.com/tc39/proposal-flatMap

https://github.com/tc39/proposal-flatMap/issues/10

>This proposal essentially gives native Arrays the methods they need to work as **Monads** (without having to extend the prototype).

They add `flatMap` on purpose  as Monad on top of the `Map`.

Pipeline-operator `|>` in the mathematical sense of function application is **natively Monad that behaves pretty well with the rock-solid structure** that majorities of programmers in JavaScript desired for, and now, Hack pipe destroys that.  No respect to Mathematics.

## Math structure of Hack pipe
F# pipe is simply mathematical function application, it behaves like Monad, so it's natural it does not behave Associative in Monoid.

Hack pipe, on the other hand, it behave like Associative and Monoid, 
```
a |> f(^) |> g(^)   == 
a |> (f(^) |> g(^)) 
```
but this is not a monoid.
Something unknown to leads:
`1 |> 3 == 3`
This is something completely different from Function application in mathematical sense.  
This one breaks the Algebraic structure that I've explained so far.
**Function application is NOT Monoid and should not behave like Monoid.**
**Function composition is Monoid but with Hack pipe, there is no such a concept anymore because it has broken the mathematics.**

With pipeline-operator in the algebraic sense,
```
a |> f |> g   ===
a |> (f . g) 
```

This is Associative in Monad layer with Function composition that itself is Associative and Monoid/Monad in both layers.

## Type of Hack pipe

I'll give it another shot.

As a type,

`A |> F |> F |> F`  is replaced to
`A * F * F * F`
`===`
`A * (F + F + F)`
where
`A * F` is function application, and
`F + F` is function composition.

Hack on the other hand,
They claim the simplicity:
`A * F * F * F`
`===`
`A * (F * F * F)`
We no longer understand what the `(F * F * F)`  is.
In fact, they say:
`(F * F * F)` itself is a syntax-error. 
Sure it should be because it doesn't make sense, and 
`(F * F * F)` is refused to be evaluated because they ignore the rule of grouping-operator.
**In other words, they overrides a rule of the operator that has the highest precedence priority in JavaScript, that I would call hijack.**
`(F * F * F)`  is not a function composition like in F# or math pipe, nor anything understandable, so Type is `?`
`A * (?)`
and **`(?)` appears to be the evaluated value of the whole expression** (such as `3`):
`? == A * (?)`
therefore
`A * (A * (A * (A * (A * (A * (A * (..?..)))))))` 
Some structure of infinite recursion.
That is the Type of the Hack pipe. Scary.


## Hijacking grouping-operator `()`

As you can see,
![image](https://user-images.githubusercontent.com/1316994/134595674-9a280ced-0fb3-4c04-ac91-9fd84e483404.png)

Internally, technically, the Hack `|>` **refuses** to evaluate `(f(%) |> g(%))` first ignoring the rule of 

### [Grouping operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Grouping)  `( )`
>The grouping operator consists of a pair of parentheses around an expression or sub-expression to override the normal operator precedence so that **expressions with lower precedence can be evaluated before an expression with higher priority.** 

**Grouping operator `( )` itself has the highest [Operator precedence](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence) in JavaScript.**

Then I hear the counter explanation to justify Hack pipe anomaly:
https://github.com/tc39/proposal-pipeline-operator/issues/227#issuecomment-926317660

>It’s just the  _old_  left-to-right evaluation rules. There aren’t any special grouping rules here. Parentheses change the grouping, but they  _never_  have changed execution order from anything other than left to right.

**"*old* left-to-right evaluation rules" that means [eager evaluation strategy](https://en.wikipedia.org/wiki/Evaluation_strategy#Eager_evaluation) of JavaScript follows the rule in the sense of both Mathematics and grouping-operator `()`.**

Eager evaluation does not conflict to **evaluation order**.

The evaluation order arises from  [Dependency graph](https://en.wikipedia.org/wiki/Dependency_graph)

>In mathematics, computer science and digital electronics, a dependency graph is a directed graph representing dependencies of several objects towards each other. It is possible to derive an **evaluation order** or the absence of an **evaluation order** that respects the given dependencies from the dependency graph.

and `()` defines the dependency graph and the structure of the code.

**Remember dependency graph or structure is completely different concept of time order.**

 Here, in the terms of "**evaluation order**", "**before**", **"after**" we discuss Not  **time order of the evaluation/excision**, but **dependency structure** of the code, which unfortunately it seems everyone in the Hack pipe proposal team share the confusion of the concept.
 As we've seen, the Hack pipe refuses to follow the evaluation order of dependency structure and I would call this **Hijacking grouping-operator `()`**.

I did explain to them, but they did not hear, then deleted my explanation. That is why I made a post here.

 [Current TC39 proposal  Hack Pipeline Operator](https://github.com/tc39/proposal-pipeline-operator) `|>` has severe problems including the process of the staging, and the entire community of JavaScript will suffer.

**EDIT (2021/9/28):**
Now they added a false statement to the MDN page of  [Grouping operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Grouping) `( )`, for the purpose of justifying their own proposal that is based on the confusion of the concept:  **"evaluation order" derived from the dependency graph or structure is completely different concept of "time order" of executions.**

I made Issues:
[Issue with "Grouping operator ( )": (invalid statements added) #9306](https://github.com/mdn/content/issues/9306)

[Implicitly misleading into confusion of concepts: "Grouping operator ( )"  #9317](https://github.com/mdn/content/issues/9317)

[Update Grouping operator ( )  #9325](https://github.com/mdn/content/pull/9325)

----


Please confirm here:
[Description confusing concepts clarified  #9389](https://github.com/mdn/content/pull/9389)

----
The point of view here has been shared in [stack overflow question](https://stackoverflow.com/questions/69384610/does-the-functionality-of-grouping-operator-in-javascript-differ-from-haske/69386130) , and [a third person confirmed the fact as the answer](https://stackoverflow.com/a/69386130/11316608
):

>Grouping parentheses mean the same thing in Haskell as they do in high school mathematics. They group a sub-expression into a single term. This is also what they mean in Javascript and most other programming language,

>A language needs other rules beyond just the grouping of sub-expressions to pin down evaluation order (if it wants to specify the order), whether it's strict or lazy. So since you need other rules to determine it anyway, **it is best (in my opinion) to think of evaluation order as a totally separate concept than grouping.** **Mixing them up seems like a shortcut when you're learning high school mathematics, but it's just a handicap in more general settings.**

Therefore, for the explanation of Grouping operator (parentheses) itself, the priority of the article should be to focus the functionality given as the meaning of  "high school mathematics".

The wording of old version "operands" of "preserved" actively misleads readers to confuse the  "high school mathematics" principle of the Grouping operator and the evaluation strategy of JavaScript runtime. 
 
If anyone think such an example is required and to be included in this page, they need to explain thoroughly for readers to avoid the confusion of concepts between the mathematical aspect and evaluation strategy that the latter is essentially off-topic here.

---

Also, my next article:

[Does the functionality of Grouping operator () in JavaScript differ from Haskell or other programming languages?](https://dev.to/stken2050/does-the-functionality-of-grouping-operator-in-javascript-differ-from-haskell-or-other-programming-languages-1f20)