Does the Hack-style pipe operator |>
take precedence over grouping operator ( )
in order of operations in JavaScript?
I'm investigating tc39/proposal-pipeline-operator - for JavaScript
Pipe Operator (|>) for JavaScript
- Stage: 2
- Specification
- Babel plugin: Implemented in v7.15. See Babel documentation.
There were two competing proposals for the pipe operator: Hack pipes and F# pipes.
The minimal/F#-style pipe-operator is just a binary operator of function application between a value x
and a function f
in algebraic sense that is:
f(x) === x |> f
g(f(x) === x |> f |> g
As this is a simple replacement of the mathematical expressions, there is nothing to relearn and so-called referential transparency is guaranteed.
Referential transparency and referential opacity are properties of parts of computer programs. An expression is called referentially transparent if it can be replaced with its corresponding value (and vice-versa) without changing the program's behavior.
Now, they have chosen the Hack-style pipe advanced to TC39 Stage2.
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,- etc.
Although the Hack-pipe proposal team claims as
Pro: The righthand side can be any expression
this means the type of |>
is no longer as simple as the type of minimal/F#-style pipe-operator:
- x : Object
- f : Function
Therefore, I need to investigate what's really going on underneath using Babel: Implemented in v7.15.
Test-1
REPL with an example code with a configuration
const f = a => a * 2;
const g = a => a + 1;
1 |> f(%) |> g(%);
1 |> (f(%) |> g(%));
transpiled to
var _ref, _ref2, _ref3, _ref4;
const f = a => a * 2;
const g = a => a + 1;
_ref2 = 1, (_ref = f(_ref2), g(_ref));
_ref4 = 1, (_ref3 = f(_ref4), g(_ref3));
which indicates
1 |> f(%) |> g(%)
1 |> (f(%) |> g(%))
the both expressions share an identical structure under the Hack-pipe.
(I have confirmed this result is on-spec and expected from one of the champion team of Hack-pipe proposal)
In the principle of Grouping operator ( ) in JavaScript, this should be invalid.
The grouping operator
( )
controls the precedence of evaluation in expressions.
The grouping ()
rules the mathematical structure (dependency graph) of expressions.
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.
Surely, there is a factor of evaluation order by the evaluation strategy (eager evaluation for JavaScript), however, the algebraic structure (dependency graph) should be changed accordingly,
|>
/ \
|> g(%)
/ \
1 f(%)
|>
/ \
1 |>
/ \
f(%) g(%)
and the transpile fact shows the Hack-pipe ignores the principle.
Test-2
So, If the Hack-pipe follows the rule of the Grouping operator in JavaScript, or any other programming languages, for the expression:
1 |> (f(%) |> g(%));
regardless of the evaluation order, the dependency graph should be:
|>
/ \
1 |>
/ \
f(%) g(%)
Now I have a log
function to show the value.
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(%)));
which transpiled to
and the console.log
result is 3
regardless of the order of the evaluation.
(f(%) |> g(%)) == 3
where
const f = a => a * 2;
const g = a => a + 1;
1 |> f(%) |> g(%); // 1 * 2 + 1 = 3
1 |> (f(%) |> g(%)); // 1 * 2 + 1 = 3 with hack-pipe
therefore,
1 |> 3 == 3
which indicates Hack-pipe is logically broken and does not make sense any more to code.
My question, or what I would like you to distinguish is:
Does the Hack-style pipe operator |>
take precedence over grouping operator ( )
in order of operations in JavaScript?
Objective answers not subjective/opinion base, please. Thanks.
For comments:
1.
We share the fact that the Grouping operator has the highest precedence according to Operator precedence.
2.
According to the tc39/proposal-pipeline-operator Hack proposal
Yes, this is a claim by a member of the champion team of the Hack pipe proposal.
Now, the claim is against the fact that I examined here, and that is why I want you distinguish, including what I miss in my investigation here.
The purpose of the question is to know the fact of the hack-pipe eliminating obscurity in interpretation or ignoring the exact implementation underneath.