{"action":"created","issue":{"url":"https://api.github.com/repos/tc39/proposal-pipeline-operator/issues/55","repository_url":"https://api.github.com/repos/tc39/proposal-pipeline-operator","labels_url":"https://api.github.com/repos/tc39/proposal-pipeline-operator/issues/55/labels{/name}","comments_url":"https://api.github.com/repos/tc39/proposal-pipeline-operator/issues/55/comments","events_url":"https://api.github.com/repos/tc39/proposal-pipeline-operator/issues/55/events","html_url":"https://github.com/tc39/proposal-pipeline-operator/issues/55","id":254433462,"number":55,"title":"Alternative pipeline strategies and operators","user":{"login":"isiahmeadows","id":4483844,"avatar_url":"https://avatars1.githubusercontent.com/u/4483844?v=4","gravatar_id":"","url":"https://api.github.com/users/isiahmeadows","html_url":"https://github.com/isiahmeadows","followers_url":"https://api.github.com/users/isiahmeadows/followers","following_url":"https://api.github.com/users/isiahmeadows/following{/other_user}","gists_url":"https://api.github.com/users/isiahmeadows/gists{/gist_id}","starred_url":"https://api.github.com/users/isiahmeadows/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/isiahmeadows/subscriptions","organizations_url":"https://api.github.com/users/isiahmeadows/orgs","repos_url":"https://api.github.com/users/isiahmeadows/repos","events_url":"https://api.github.com/users/isiahmeadows/events{/privacy}","received_events_url":"https://api.github.com/users/isiahmeadows/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":1,"created_at":"2017-08-31T18:52:24Z","updated_at":"2017-09-01T09:21:58Z","closed_at":null,"author_association":"NONE","body":"Bringing over a summary of some of the insane amounts of discussion that occurred in the [bind operator proposal's repo](https://github.com/tc39/proposal-bind-operator) regarding function pipelining, since it's far more relevant here than there now (since this is a TC39 repo now dedicated to the topic), and I think we could use a historical record and starting point for this. Apologies for the long length.\r\n\r\n---\r\n\r\n## Pipeline strategies\r\n\r\nThere are three primary strategies you could use to pipeline function calls:\r\n\r\n<sub>*(For expository purposes, I'm using `@` for all three variants to make them less visibly different while still making it seem like a fitting operator. Note that I'm not actually proposing it, since it conflicts with decorators.)*</sub>\r\n\r\n1. `foo@bar(...)` &harr; `bar.call(foo, ...)`\r\n\r\n    This was what was initially proposed in the bind operator proposal. It is fairly object-oriented in that it views callees more like extension methods than just functions, and calls them accordingly – the context (`foo` in this case) is passed as `this`, and the arguments as you would expect.\r\n\r\n1. `foo@bar(...)` &harr; `bar(foo, ...)`\r\n\r\n    This was proposed by @gajus in [this particular comment](https://github.com/tc39/proposal-bind-operator/issues/24#issuecomment-281202427). It is more procedural, and can be viewed as threading a value through several functions much like [Clojure's thread-first macro](https://clojuredocs.org/clojure.core/-%3E).\r\n\r\n1. `foo@bar(...)` &harr; `bar(...)(foo)`\r\n\r\n    This was proposed by @gilbert in this repo. It is more functional in nature, since it involves piping through a series of single-arg functions, usually returned from calling another function (in this case, from `bar(...)`).\r\n\r\n### Pros and Cons\r\n\r\nOf course, these are not all equal, and they each have their strengths and weaknesses. None of these are magic silver bullets, and they all have their shortcomings. [I did go into some detail on this previously](https://github.com/tc39/proposal-bind-operator/issues/24#issuecomment-281385344), but I thought I'd relay it here, too.\r\n\r\n1. `foo@bar(...)` &harr; `bar.call(foo, ...)`\r\n\r\n    Pros:\r\n\r\n    - It plays well with the philosophy that it's an extension method of sorts. (This could also be considered a con by some.)\r\n    - It lends itself well to borrowing generic native prototype methods like `Array.prototype.join` and `Object.prototype.toString`.\r\n    - It reduces the need for `func.call`, `func.apply`, and `Reflect.apply`.\r\n\r\n    Cons:\r\n\r\n    - Existing third-party library support is fairly low. (This could change depending on if this variant is accepted.)\r\n    - The heavily object-oriented appearance is likely to be contentious, for similar reasons to why ES6 classes [have met some sharp criticism](https://github.com/joshburgess/not-awesome-es6-classes).\r\n    - It naturally begets a binding variant like `foo@bar` being equivalent to `bar.bind(foo)`. This kind of behavior is much more contentious, and feel free to explore the [bind operator proposal's issues](https://github.com/tc39/proposal-bind-operator/issues) to see this in action.\r\n    - Due to its reliance on `this`, it's impossible to define such utilities using arrow functions, and inline utilities are pretty verbose ([which could be rectified](https://github.com/gilbert/es-explicit-this)):\r\n        ```js\r\n        foo()\r\n        @function () { return this + 1 }()\r\n        @bar()\r\n        ```\r\n\r\n1. `foo@bar(...)` &harr; `bar(foo, ...)`\r\n\r\n    Pros:\r\n\r\n    - It lends itself well to concise helpers defined via arrow functions.\r\n    - It avoids most of the issues with `this`, including much of the contention.\r\n    - It encourages function-based APIs without becoming functional enough to be contentious.\r\n    - It works well with many existing libraries such as Three.js, Lodash, and the like. (This is a pretty weak plus, since libraries can adapt to any of these.)\r\n\r\n    Cons:\r\n\r\n    - Use of native prototype methods have to be wrapped somehow. (This is a pretty weak minus, since `var dethisify = Function.bind.bind(Function.call)` can trivially wrap them.)\r\n    - It looks somewhat object-oriented even though it avoids `this`. (This could turn off some functional programming fans.)\r\n    - It may surprise newcomers already familiar with object-oriented languages, due to it not using `this`.\r\n    - Defining inline helpers is slightly awkward:\r\n        ```js\r\n        foo()\r\n        @(x => x + 1)()\r\n        @bar()\r\n        ```\r\n\r\n1. `foo@bar(...)` &harr; `bar(...)(foo)`\r\n\r\n    Pros:\r\n\r\n    - It lends itself well to functional idioms. (This could be considered a con to some.)\r\n    - It avoids `this` and related problems entirely.\r\n    - It allows easy use of inline helpers:\r\n        ```js\r\n        foo()\r\n        @(x => x + 1)\r\n        @bar()\r\n        ```\r\n\r\n    Cons:\r\n\r\n    - The functional nature of it is likely to be contentious.\r\n    - Existing library support exists, but is limited. (This could change depending on if this variant is selected.)\r\n    - It requires currying for calls to not depend on this specific form for ease of use. (This is a similar issue to the `this` dependence of the first option.)\r\n    - It's substantially harder for engines to optimize, since it enforces an observable closure allocation at least, and currying is hard to optimize without native support. (Engines can adapt for the former, and a language-level curry proposal would solve the latter.)\r\n\r\n    In addition, this could be simulated by using a native composition operator/method and immediately calling it with the value to pipe through, although it would cause the functions to all create their closures *before* any of them could be evaluated. (This does make optimization a bit more difficult without inlining first.)\r\n\r\n## Alternate operators\r\n\r\nAs expected, there have been numerous other operators already suggested for signaling pipelining. Here's a list of many of them:\r\n\r\n- `::` – proposed with the original bind proposal\r\n- `~>` – proposed in [this issue](https://github.com/tc39/proposal-bind-operator/issues/26)\r\n- `->` – proposed in [this comment](https://github.com/tc39/proposal-bind-operator/issues/24#issuecomment-141331472)\r\n- `|>` – proposed originally in this repo\r\n- `..` – proposed in [this issue](https://github.com/tc39/proposal-bind-operator/issues/10)\r\n- `&` – proposed in [this issue](https://github.com/tc39/proposal-bind-operator/issues/23), although it's obviously a no-go\r\n\r\nI've noted that `~>` is a [bit awkward to type](https://github.com/tc39/proposal-bind-operator/issues/26#issuecomment-141617477), and a few others pointed out that `..` runs the risk of confusion with spread, a potential future range syntax. The remaining 3 (`::`, `->`, and `|>`) are likely more viable, although I'll point out that `|>` is itself a little awkward to type in my personal experience (small hands :open_hands: :smile:).\r\n"},"comment":{"url":"https://api.github.com/repos/tc39/proposal-pipeline-operator/issues/comments/326533579","html_url":"https://github.com/tc39/proposal-pipeline-operator/issues/55#issuecomment-326533579","issue_url":"https://api.github.com/repos/tc39/proposal-pipeline-operator/issues/55","id":326533579,"user":{"login":"flying-sheep","id":291575,"avatar_url":"https://avatars0.githubusercontent.com/u/291575?v=4","gravatar_id":"","url":"https://api.github.com/users/flying-sheep","html_url":"https://github.com/flying-sheep","followers_url":"https://api.github.com/users/flying-sheep/followers","following_url":"https://api.github.com/users/flying-sheep/following{/other_user}","gists_url":"https://api.github.com/users/flying-sheep/gists{/gist_id}","starred_url":"https://api.github.com/users/flying-sheep/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/flying-sheep/subscriptions","organizations_url":"https://api.github.com/users/flying-sheep/orgs","repos_url":"https://api.github.com/users/flying-sheep/repos","events_url":"https://api.github.com/users/flying-sheep/events{/privacy}","received_events_url":"https://api.github.com/users/flying-sheep/received_events","type":"User","site_admin":false},"created_at":"2017-09-01T09:21:58Z","updated_at":"2017-09-01T09:21:58Z","author_association":"NONE","body":"For prior art I’d also like to mention R’s [`magrittr`](https://cran.r-project.org/web/packages/magrittr/vignettes/magrittr.html), cornerstone to the very popular “tidyverse” programming style. It uses a mixture of 2 and 3, with a few extensions:\r\n\r\n1. `str %>% tolower` and `str %>% tolower()` are the same thing: `tolower(str)`\r\n2. `lst %>% sort(TRUE)` works like variant 2: `sort(lst, TRUE)`\r\n2. `str %>% grep('pat', .)` is a way to use the LHS as a specific instead of first parameter: `grep('pat', str)`\r\n3. `num %>% { . + 1 }` is a way to use expressions in the pipe: `num + 1`\r\n4. `. %>% foo` is an anonymous function (useless for us because we have `=>`)\r\n\r\nI’m not proposing to adapt this. I think it’s too complicated, and especially confusing with higher-order functions:\r\n\r\n```js\r\nconst adder = rhs => lhs => lhs + rhs\r\nconst plus1 = adder(1)\r\n\r\n// work as expected\r\n2@plus1     //→ plus1(2)\r\n3@plus1()   //→ plus1(3)\r\n// the first one is a bug bound to happen\r\n4@adder(2)  //→ adder(2, 4)\r\n4@(adder(2))  //→ adder(2)(4)\r\n```"}}
{"actor":{"display_login":"flying-sheep"}}