Piping is useful when composing many small pure functions together, one problem
with this is the evaluation needs to be read from the inner most expression
value in reverse to the outer most function call. Given the following statement
we can see that it would be read as 'call math round then call math square then
pass in PI', whereas the order of execution is in reverse.
```javascript
const myNumber = Math.round(Math.sqrt(Math.PI));
```
Unix has long provided a piping mechanism to achieve that, for example: `ps aux
| grep node`, as well as F# and the Elixir programming language, both provide
the `|>` pipe greater-than operator which is very readable.
My proposal would be to use the slightly more verbose `|>` pipe-greater than
syntax, it provides a convenient direction of travel for the expression on the
left side, into the expression on the right, F# also provides a `<|`, which
pipes in the opposite direction though I’ve not really seen very good use cases
for this operator.
```javascript
const myNumber = Math.PI |> Math.sqrt |> Math.round;
```
The left side of the operator should always be a primitive data type or data
structure, these could be any of the following: `Boolean`, `Null`, `undefined`,
`Number`, `String`, `Symbol` or `Object`. Since functions are standard objects
they can be passed in as the initial value, as long as the function on the
right handles the calling on that function.
It also provides a way to either log, process, or do anything with the data
from the last expression on the left at various stages of the execution without
adding additional brackets in and around the calls, for example.
```javascript
function logger (callback) {
return function (value) {
callback(value);
return value;
};
}
Math.PI
|> logger(console.log);
|> Math.sqrt
|> logger(console.log);
|> Math.round
|> logger(console.log);
```
While a slightly contrived example as we certainly wouldn't write code that
looks like:
```javascript
logger(Math.round(logger(Math.sqrt(logger(Math.PI)))));
```
We would instead assign to variables at each stage of execution:
```javascript
const PI = Math.PI;
logger(PI);
const squaredPI = Math.sqrt(PI);
logger(squaredPI);
const roundedSquaredPI = Math.round(squaredPI);
logger(roundedSquaredPI);
```
However with this clarity we have unfortunately had to create additional
constants within this lexical block, whereas simple value passing between pure
functions provides a very clean and readable approach and allows easier updates
in the future if we wanted to add additional processing within the chain, for
example Express middleware composition.
Would love to hear some thoughts on this?
David
* [F# pipe
operator](https://docs.microsoft.com/en-gb/dotnet/fsharp/language-reference/functions/index#function-composition-and-pipelining)
* [Elixir pipe
operator](https://elixir-lang.org/getting-started/enumerables-and-streams.html#the-pipe-operator)
* [Unix pipeline](https://en.wikipedia.org/wiki/Pipeline_(Unix))
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss