Pipe operator for JavaScript

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Pipe operator for JavaScript

David White
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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pipe operator for JavaScript

Logan Smyth
There's been talk of this before here and in https://github.com/gilbert/es-pipeline-operator among other places. Most recently this was posted, which sounds like promising progress: https://github.com/gilbert/es-pipeline-operator/issues/33#issuecomment-306986211

On Tue, Jul 11, 2017 at 1:02 PM, David White <[hidden email]> wrote:
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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Pipe operator for JavaScript

David White
Oh apologies for not taking a few moments to use the search facility. The linked github sounds extremely promising and certainly captures far more use cases than I initially intended.

Thanks Logan.

David


On 11 Jul 2017, at 21:10, Logan Smyth <[hidden email]> wrote:

There's been talk of this before here and in https://github.com/gilbert/es-pipeline-operator among other places. Most recently this was posted, which sounds like promising progress: https://github.com/gilbert/es-pipeline-operator/issues/33#issuecomment-306986211

On Tue, Jul 11, 2017 at 1:02 PM, David White <[hidden email]> wrote:
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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Loading...