├── .editorconfig ├── .gitignore ├── additional-feature-ba.md ├── additional-feature-bc.md ├── additional-feature-bp.md ├── additional-feature-np.md ├── additional-feature-pf.md ├── additional-feature-ts.md ├── core-real-examples.md ├── core-syntax.md ├── goals.md ├── license.md ├── nomenclature.md ├── package-lock.json ├── package.json ├── readme.md ├── relations.md ├── spec.html └── term-rewriting.md /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | trim_trailing_whitespace = true 7 | charset = utf-8 8 | indent_style = space 9 | indent_size = 2 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /out/ 3 | /npm-debug.log 4 | 5 | deploy_key 6 | -------------------------------------------------------------------------------- /additional-feature-ba.md: -------------------------------------------------------------------------------- 1 | |Name | Status | Features | Purpose | 2 | | ----------------------- | ------- | ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | 3 | |[Core Proposal][] | Stage 0 | Infix pipelines `… \|> …`
Lexical topic `#` | **Unary** function/expression **application** | 4 | |[Additional Feature BC][]| None | Bare constructor calls `… \|> new …` | Tacit application of **constructors** | 5 | |[Additional Feature BA][]| None | Bare awaited calls `… \|> await …` | Tacit application of **async functions** | 6 | |[Additional Feature BP][]| None | Block pipeline steps `… \|> {…}` | Application of **statement blocks** | 7 | |[Additional Feature PF][]| None | Pipeline functions `+> ` | **Partial** function/expression **application**
Function/expression **composition**
**Method extraction** | 8 | |[Additional Feature TS][]| None | Pipeline `try` statements | Tacit application to **caught errors** | 9 | |[Additional Feature NP][]| None | N-ary pipelines `(…, …) \|> …`
Lexical topics `##`, `###`, and `...`| **N-ary** function/expression **application** | 10 | 11 | # Additional Feature BA 12 | ECMAScript No-Stage Proposal. Living Document. J. S. Choi, 2018-12. 13 | 14 | This document is not yet intended to be officially proposed to TC39 yet; it merely shows a possible 15 | extension of the [Core Proposal][] in the event that the Core Proposal is accepted. 16 | 17 | An additional feature – **bare awaited calls** – would make async function calls terser. It adds 18 | another mode to bare style: if a bare-style pipeline step is preceded by a 19 | `await`, then instead of a mere function call, it is an awaited function call. 20 | `value |> await object.asyncFunction` is equivalent to `await 21 | object.asyncFunction(value)`. This would be backwards compatible with the [Core 22 | Proposal][] as well as all other [additional features][]. 23 | 24 | [Additional Feature BA is **formally specified in in the draft 25 | specification**][formal BC]. 26 | 27 | 28 | 29 | 30 | 34 | 35 |
With smart pipelines 31 | Status quo 32 | 33 |
36 | 37 | ```js 38 | value 39 | |> # + '!' 40 | |> new User.Message(#) 41 | |> await stream.write 42 | |> console.log; 43 | ``` 44 | 45 | 46 | 47 | ```js 48 | console.log( 49 | await stream.write( 50 | new User.Message( 51 | value + '!' 52 | ) 53 | ) 54 | ); 55 | ``` 56 | 57 |
58 | 59 | If a pipeline step starts with `await`, followed by a mere identifier, optionally with 60 | a chain of properties, and with no parentheses or brackets, then that identifier 61 | is interpreted to be a **bare awaited function call**. 62 | 63 | That is: **if a pipeline** is of the form\ 64 | **_topic_ `|>` `await` _identifier_**\ 65 | or **_topic_ `|>` `await` _identifier0_`.`_identifier1_**\ 66 | or **_topic_ `|>` `await` _identifier0_`.`_identifier1_`.`_identifier2_**\ 67 | or so forth,\ 68 | then the pipeline is a bare async function call. 69 | 70 | | Valid [topic style][] | Valid [bare style][] | Invalid pipeline 71 | | ----------------------- | ---------------------------------------- | -------------------- 72 | |`… \|> await af(#)` |`… \|> await af` | `… \|> await af()` 🚫 73 | | ″″ | ″″ | `… \|> (await f)` 🚫 74 | | ″″ | ″″ | `… \|> (await f())` 🚫 75 | | ″″ | ″″ | `… \|> await (f)` 🚫 76 | | ″″ | ″″ | `… \|> await (f())` 🚫 77 | |`… \|> af \|> await #` | ″″ | `… \|> af \|> await` 🚫 78 | |`… \|> await o.f(#)` |`… \|> await o.f` | `… \|> await o.f()` 🚫 79 | |`… \|> await o.make()(#)`|`const af = o.make(); … \|> await af` | `… \|> await o.make()` 🚫 80 | |`… \|> await new o.make()(#)`|`const af = new o.make(); … \|> await af`| `… \|> new await o.make()` 🚫 81 | 82 | ["data-to-ink" visual ratio]: https://www.darkhorseanalytics.com/blog/data-looks-better-naked 83 | ["don’t break my code"]: ./goals.md#dont-break-my-code 84 | ["don’t make me overthink"]: ./goals.md#dont-make-me-overthink 85 | ["don’t shoot me in the foot"]: ./goals.md#dont-shoot-me-in-the-foot 86 | ["make my code easier to read"]: ./goals.md#make-my-code-easier-to-read 87 | [`??:`]: https://github.com/tc39/proposal-nullish-coalescing/pull/23 88 | [`do` expression]: ./relations.md#do-expressions 89 | [`do` expressions]: ./relations.md#do-expressions 90 | [`for` iteration statements]: https://tc39.github.io/ecma262/#sec-iteration-statements 91 | [`in` relational operator]: https://tc39.github.io/ecma262/#sec-relational-operators 92 | [`match` expressions]: ./relations.md#pattern-matching 93 | [`new.target`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new.target 94 | [Additional Feature BA]: ./additional-feature-ba.md 95 | [Additional Feature BC]: ./additional-feature-bc.md 96 | [Additional Feature BP]: ./additional-feature-bp.md 97 | [Additional Feature NP]: ./additional-feature-np.md 98 | [Additional Feature PF]: ./additional-feature-pf.md 99 | [Additional Feature TS]: ./additional-feature-ts.md 100 | [additional features]: ./readme.md#additional-features 101 | [annevk]: https://github.com/annevk 102 | [antecedent]: https://en.wikipedia.org/wiki/Antecedent_(grammar) 103 | [arbitrary associativity]: ./goals.md#arbitrary-associativity 104 | [ASI]: https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion 105 | [associative property]: https://en.wikipedia.org/wiki/Associative_property 106 | [async pipeline functions]: ./additional-feature-pf.md 107 | [Babel plugin]: https://github.com/valtech-nyc/babel/ 108 | [Babel update summary]: https://github.com/babel/proposals/issues/29#issuecomment-372828328 109 | [background]: ./readme.md 110 | [backward compatibility]: ./goals.md#backward-compatibility 111 | [bare awaited function call]: ./core-syntax.md#bare-style 112 | [bare constructor call]: ./core-syntax.md#bare-style 113 | [bare function call]: ./core-syntax.md#bare-style 114 | [bare style]: ./core-syntax.md#bare-style 115 | [binding]: https://en.wikipedia.org/wiki/Binding_(linguistics) 116 | [block parameters]: ./relations.md#block-parameters 117 | [Clojure compact function]: https://clojure.org/reference/reader#_dispatch 118 | [Clojure pipe]: https://clojuredocs.org/clojure.core/as-%3E 119 | [completion records]: https://timothygu.me/es-howto/#completion-records-and-shorthands 120 | [concatenative programming]: https://en.wikipedia.org/wiki/Concatenative_programming_language 121 | [conceptual generality]: ./goals.md#conceptual-generality 122 | [Core Proposal]: ./readme.md 123 | [core-real-examples.md]: ./core-real-examples.md 124 | [currying]: https://en.wikipedia.org/wiki/Currying 125 | [cyclomatic complexity]: https://en.wikipedia.org/wiki/Cyclomatic_complexity#Applications 126 | [cyclomatic simplicity]: ./goals.md#cyclomatic-simplicity 127 | [dataflow programming]: https://en.wikipedia.org/wiki/Dataflow_programming 128 | [distinguishable punctuators]: ./goals.md#distinguishable-punctuators 129 | [don’t break my code]: ./goals.md#dont-break-my-code 130 | [DSLs]: https://en.wikipedia.org/wiki/Domain-specific_language 131 | [early error rule]: ./goals.md#static-analyzability 132 | [early error rules]: ./goals.md#static-analyzability 133 | [early error]: ./goals.md#static-analyzability 134 | [early errors]: ./goals.md#static-analyzability 135 | [ECMAScript _Identifier Name_]: https://tc39.github.io/ecma262/#prod-IdentifierName 136 | [ECMAScript _Identifier Reference_]: https://tc39.github.io/ecma262/#prod-IdentifierReference 137 | [ECMAScript _Member Expression_]: https://tc39.github.io/ecma262/#prod-MemberExpression 138 | [ECMAScript § The Syntactic Grammar]: https://tc39.github.io/ecma262/#sec-syntactic-grammar 139 | [ECMAScript `new` operator, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-new-operator-runtime-semantics-evaluation 140 | [ECMAScript arrow functions, § SS: Contains]: https://tc39.github.io/ecma262/#sec-arrow-function-definitions-static-semantics-contains 141 | [ECMAScript Assignment-level Expressions]: https://tc39.github.io/ecma262/#sec-assignment-operators 142 | [ECMAScript block parameters]: https://github.com/samuelgoto/proposal-block-params 143 | [ECMAScript Blocks, § RS: Block Declaration Instantiation]: https://tc39.github.io/ecma262/#sec-blockdeclarationinstantiation 144 | [ECMAScript Blocks, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-block-runtime-semantics-evaluation 145 | [ECMAScript Declarative Environment Records]: https://tc39.github.io/ecma262/#sec-declarative-environment-records 146 | [ECMAScript function binding]: https://github.com/zenparsing/es-function-bind 147 | [ECMAScript Function Calls, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-function-calls-runtime-semantics-evaluation 148 | [ECMAScript Function Environment Records]: https://tc39.github.io/ecma262/#sec-function-environment-records 149 | [ECMAScript Functions and Classes § Generator Function Definitions]: https://tc39.github.io/ecma262/#sec-generator-function-definitions 150 | [ECMAScript Get This Environment]: https://tc39.github.io/ecma262/#sec-getthisenvironment 151 | [ECMAScript headless-arrow proposal]: https://bterlson.github.io/headless-arrows/ 152 | [ECMAScript Lexical Environments]: https://tc39.github.io/ecma262/#sec-lexical-environments 153 | [ECMAScript Lexical Grammar]: https://tc39.github.io/ecma262/#sec-ecmascript-language-lexical-grammar 154 | [ECMAScript LHS expressions]: https://tc39.github.io/ecma262/#sec-left-hand-side-expressions 155 | [ECMAScript Lists and Records]: https://tc39.github.io/ecma262/#sec-list-and-record-specification-type 156 | [ECMAScript Notational Conventions, § Algorithm Conventions]: https://tc39.github.io/ecma262/#sec-algorithm-conventions-abstract-operations 157 | [ECMAScript Notational Conventions, § Grammars]: https://tc39.github.io/ecma262/#sec-syntactic-and-lexical-grammars 158 | [ECMAScript Notational Conventions, § Lexical Grammar]: https://tc39.github.io/ecma262/#sec-lexical-and-regexp-grammars 159 | [ECMAScript Notational Conventions, § Runtime Semantics]: https://tc39.github.io/ecma262/#sec-runtime-semantics 160 | [ECMAScript optional `catch` binding]: https://github.com/tc39/proposal-optional-catch-binding 161 | [ECMAScript partial application]: https://github.com/tc39/proposal-partial-application 162 | [ECMAScript pattern matching]: https://github.com/tc39/proposal-pattern-matching 163 | [ECMAScript Primary Expressions]: https://tc39.github.io/ecma262/#prod-PrimaryExpression 164 | [ECMAScript Property Accessors, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-property-accessors-runtime-semantics-evaluation 165 | [ECMAScript Punctuators]: https://tc39.github.io/ecma262/#sec-punctuators 166 | [ECMAScript static semantic rules]: https://tc39.github.io/ecma262/#sec-static-semantic-rules 167 | [Elixir pipe]: https://hexdocs.pm/elixir/Kernel.html#%7C%3E/2 168 | [Elm pipe]: http://elm-lang.org/docs/syntax#infix-operators 169 | [essential complexity]: https://en.wikipedia.org/wiki/Essential_complexity 170 | [expressions and operators (MDN)]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators 171 | [expressive versatility]: ./goals.md#expressive-versatility 172 | [F# pipe]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/functions/index#function-composition-and-pipelining 173 | [first pipe-operator proposal]: https://github.com/tc39/proposal-pipeline-operator/blob/37119110d40226476f7af302a778bc981f606cee/README.md 174 | [footguns]: https://en.wiktionary.org/wiki/footgun 175 | [formal BA]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-ba 176 | [formal BC]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-bc 177 | [formal BP]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-bp 178 | [formal CP]: https://jschoi.org/18/es-smart-pipelines/spec#introduction 179 | [formal NP]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-np 180 | [formal PF]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-pf 181 | [formal pipeline specification]: https://jschoi.org/18/es-smart-pipelines/spec 182 | [formal TS]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-ts 183 | [forward compatibility]: ./goals.md#forward-compatibility 184 | [forward compatible]: ./goals.md#forward-compatibility 185 | [function bind operator `::`]: ./relations.md#function-bind-operator 186 | [function binding]: ./relations.md#function-binding 187 | [function composition]: ./relations.md#function-composition 188 | [functional programming]: https://en.wikipedia.org/wiki/Functional_programming 189 | [gajus functional composition]: https://github.com/gajus/babel-plugin-transform-function-composition 190 | [garden-path syntax]: https://en.wikipedia.org/wiki/Garden_path_sentence 191 | [GitHub issue tracker]: https://github.com/tc39/proposal-pipeline-operator/issues 192 | [goals]: ./goals.md 193 | [Hack pipe]: https://docs.hhvm.com/hack/operators/pipe-operator 194 | [Huffman coding]: https://en.wikipedia.org/wiki/Huffman_coding 195 | [human writability]: ./goals.md#human-writability 196 | [i-am-tom functional composition]: https://github.com/fantasyland/ECMAScript-proposals/issues/1#issuecomment-306243513 197 | [identity function]: https://en.wikipedia.org/wiki/Identity_function 198 | [IIFEs]: https://en.wikipedia.org/wiki/Immediately-invoked_function_expression 199 | [immutable objects]: https://en.wikipedia.org/wiki/Immutable_object 200 | [incidental complexity]: https://en.wikipedia.org/wiki/Incidental_complexity 201 | [intro]: readme.md 202 | [isiahmeadows functional composition]: https://github.com/isiahmeadows/function-composition-proposal 203 | [jashkenas]: https://github.com/jashkenas 204 | [jQuery + CP]: ./core-real-examples.md#jquery 205 | [jQuery]: https://jquery.com/ 206 | [jquery/src/core/access.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/access.js 207 | [jquery/src/core/init.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/init.js 208 | [jquery/src/core/parseHTML.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/parseHTML.js 209 | [JS Foundation]: https://js.foundation/ 210 | [Julia pipe]: https://docs.julialang.org/en/stable/stdlib/base/#Base.:|> 211 | [lexical topic]: https://jschoi.org/18/es-smart-pipelines/spec#sec-lexical-topics 212 | [lexically hygienic]: https://en.wikipedia.org/wiki/Hygienic_macro 213 | [littledan invitation]: https://github.com/tc39/proposal-pipeline-operator/issues/89#issuecomment-363853394 214 | [littledan]: https://github.com/littledan 215 | [LiveScript pipe]: http://livescript.net/#operators-piping 216 | [Lodash + CP + BP + PF]: ./additional-feature-pf.md#lodash-core-proposal--additional-feature-bppf 217 | [Lodash + CP + BP + PP + PF + NP]: ./additional-feature-np.md#lodash-core-proposal--additional-features-bppppfmt 218 | [Lodash + CP]: ./core-real-examples.md#lodash 219 | [Lodash]: https://lodash.com/ 220 | [mAAdhaTTah]: https://github.com/mAAdhaTTah/ 221 | [make my code easier to read]: ./goals.md#make-my-code-easier-to-read 222 | [MDN operator precedence]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence 223 | [MDN operator precedence]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table 224 | [method-extraction inline caching]: https://github.com/tc39/proposal-bind-operator/issues/46 225 | [mindeavor]: https://github.com/gilbert 226 | [mode errors]: https://en.wikipedia.org/wiki/Mode_(computer_interface)#Mode_errors 227 | [motivation]: ./readme.md 228 | [Node-stream piping]: https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options 229 | [Node.js `util.promisify`]: https://nodejs.org/api/util.html#util_util_promisify_original 230 | [nomenclature]: ./nomenclature.md 231 | [novice learnability]: ./goals.md#novice-learnability 232 | [nullish coalescing proposal]: https://github.com/tc39/proposal-nullish-coalescing/ 233 | [object initializers’ Computed Property Contains rule]: https://tc39.github.io/ecma262/#sec-object-initializer-static-semantics-computedpropertycontains 234 | [OCaml pipe]: http://blog.shaynefletcher.org/2013/12/pipelining-with-operator-in-ocaml.html 235 | [operator precedence]: ./core-syntax.md#operator-precedence-and-associativity 236 | [opt-in behavior]: ./goals.md#opt-in-behavior 237 | [optional `catch` binding]: ./relations.md#optional-catch-binding 238 | [optional-chaining syntax proposal]: https://github.com/tc39/proposal-optional-chaining 239 | [other browsers’ console variables]: https://www.andismith.com/blogs/2011/11/25-dev-tool-secrets/ 240 | [other ECMAScript proposals]: ./relations.md#other-ecmascript-proposals 241 | [other goals]: ./goals.md#other-goals 242 | [pattern matching]: ./relations.md#pattern-matching 243 | [partial function application]: ./goals.md#partial-function-application 244 | [PEP 20]: https://www.python.org/dev/peps/pep-0020/ 245 | [Perl 6 pipe]: https://docs.perl6.org/language/operators#infix_==> 246 | [Perl 6 topicization]: https://www.perl.com/pub/2002/10/30/topic.html/ 247 | [Perl 6’s given block]: https://docs.perl6.org/language/control#given 248 | [pipeline functions]: ./additional-feature-pf.md 249 | [Pipeline Proposal 1]: https://github.com/tc39/proposal-pipeline-operator/wiki#proposal-1-f-sharp-only 250 | [Pipeline Proposal 4]: https://github.com/tc39/proposal-pipeline-operator/wiki#proposal-4-smart-mix 251 | [pipeline syntax]: ./core-syntax.md 252 | [pipelines]: ./readme.md 253 | [previous pipeline-placeholder discussions]: https://github.com/tc39/proposal-pipeline-operator/issues?q=placeholder 254 | [primary topic]: ./readme.md 255 | [private class fields]: https://github.com/tc39/proposal-class-fields/ 256 | [pure functions]: https://en.wikipedia.org/wiki/Pure_function 257 | [R pipe]: https://cran.r-project.org/web/packages/magrittr/vignettes/magrittr.html 258 | [Ramda + CP + BP + PF + NP]: ./additional-feature-np.md#ramda-core-proposal--additional-features-bppfmt 259 | [Ramda + CP + BP + PF]: ./additional-feature-pf.md#ramda-core-proposal--additional-feature-bppf 260 | [Ramda wiki cookbook]: https://github.com/ramda/ramda/wiki/Cookbook 261 | [Ramda]: http://ramdajs.com/ 262 | [relations to other work]: ./relations.md 263 | [REPLs]: https://en.wikipedia.org/wiki/Read–eval–print_loop 264 | [rest topic]: ./additional-feature-np.md 265 | [reverse Polish notation]: https://en.wikipedia.org/wiki/Reverse_Polish_notation 266 | [robust method extraction]: https://github.com/tc39/proposal-pipeline-operator/issues/110#issuecomment-374367888 267 | [Ron Buckton]: https://github.com/rbuckton 268 | [secondary topic]: ./additional-feature-np.md 269 | [semantic clarity]: ./goals.md#semantic-clarity 270 | [simonstaton functional composition]: https://github.com/simonstaton/Function.prototype.compose-TC39-Proposal 271 | [simple scoping]: ./goals.md#simple-scoping 272 | [sindresorhus]: https://github.com/sindresorhus 273 | [smart step syntax]: ./core-syntax.md 274 | [smart pipelines]: ./readme.md#smart-pipelines 275 | [Standard Style]: https://standardjs.com/ 276 | [static analyzability]: ./goals.md#static-analyzability 277 | [statically analyzable]: ./goals.md#static-analyzability 278 | [statically detectable early errors]: ./goals.md#static-analyzability 279 | [syntactic locality]: ./goals.md#syntactic-locality 280 | [tacit programming]: https://en.wikipedia.org/wiki/Tacit_programming 281 | [TC39 60th meeting, pipelines]: https://tc39.github.io/tc39-notes/2017-09_sep-26.html#11iia-pipeline-operator 282 | [TC39 process]: https://tc39.github.io/process-document/ 283 | [tc39/proposal-decorators#30]: tc39/proposal-decorators#30 284 | [tc39/proposal-decorators#42]: tc39/proposal-decorators#42 285 | [tc39/proposal-decorators#60]: tc39/proposal-decorators#60 286 | [Tennent correspondence principle]: http://gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html 287 | [term rewriting]: ./term-rewriting.md 288 | [terse composition]: ./goals.md#terse-composition 289 | [terse function application]: ./goals.md#terse-function-application 290 | [terse function calls]: ./goals.md#terse-function-calls 291 | [terse method extraction]: ./goals.md#terse-method-extraction 292 | [terse parentheses]: ./goals.md#terse-parentheses 293 | [terse partial application]: ./goals.md#terse-partial-application 294 | [terse variables]: ./goals.md#terse-variables 295 | [tertiary topic]: ./additional-feature-np.md 296 | [TheNavigateur functional composition]: https://github.com/TheNavigateur/proposal-pipeline-operator-for-function-composition 297 | [topic and comment]: https://en.wikipedia.org/wiki/Topic_and_comment 298 | [topic references in other programming languages]: ./relations.md#topic-references-in-other-programming-languages 299 | [topic style]: ./core-syntax.md#topic-style 300 | [topic variables in other languages]: https://rosettacode.org/wiki/Topic_variable 301 | [topic-token bikeshedding]: https://github.com/tc39/proposal-pipeline-operator/issues/91 302 | [Underscore.js + CP + BP + PP]: ./additional-feature-pp.md#underscorejs-core-proposal--additional-feature-bppp 303 | [Underscore.js + CP]: ./core-real-examples.md#underscorejs 304 | [Underscore.js]: http://underscorejs.org 305 | [Unix pipe]: https://en.wikipedia.org/wiki/Pipeline_(Unix 306 | [untangled flow]: ./goals.md#untangled-flow 307 | [Visual Basic’s `select` statement]: https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/select-case-statement 308 | [WebKit console variables]: https://webkit.org/blog/829/web-inspector-updates/ 309 | [WHATWG Fetch + CP]: ./core-real-examples.md#whatwg-fetch-standard 310 | [WHATWG Fetch Standard]: https://fetch.spec.whatwg.org/ 311 | [WHATWG Streams + CP + BP + PF + NP]: ./additional-feature-np.md#whatwg-streams-standard-core-proposal--additional-features-bppfmt 312 | [WHATWG Streams + CP + BP + PF]: ./additional-feature-pf.md#whatwg-streams-standard-core-proposal--additional-feature-bppf 313 | [WHATWG Streams Standard]: https://stream.spec.whatwg.org/ 314 | [WHATWG-stream piping]: https://streams.spec.whatwg.org/#pipe-chains 315 | [Wikipedia: term rewriting]: https://en.wikipedia.org/wiki/Term_rewriting 316 | [zero runtime cost]: ./goals.md#zero-runtime-cost 317 | -------------------------------------------------------------------------------- /additional-feature-bc.md: -------------------------------------------------------------------------------- 1 | |Name | Status | Features | Purpose | 2 | | ----------------------- | ------- | ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | 3 | |[Core Proposal][] | Stage 0 | Infix pipelines `… \|> …`
Lexical topic `#` | **Unary** function/expression **application** | 4 | |[Additional Feature BC][]| None | Bare constructor calls `… \|> new …` | Tacit application of **constructors** | 5 | |[Additional Feature BA][]| None | Bare awaited calls `… \|> await …` | Tacit application of **async functions** | 6 | |[Additional Feature BP][]| None | Block pipeline steps `… \|> {…}` | Application of **statement blocks** | 7 | |[Additional Feature PF][]| None | Pipeline functions `+> ` | **Partial** function/expression **application**
Function/expression **composition**
**Method extraction** | 8 | |[Additional Feature TS][]| None | Pipeline `try` statements | Tacit application to **caught errors** | 9 | |[Additional Feature NP][]| None | N-ary pipelines `(…, …) \|> …`
Lexical topics `##`, `###`, and `...`| **N-ary** function/expression **application** | 10 | 11 | # Additional Feature BC 12 | ECMAScript No-Stage Proposal. Living Document. J. S. Choi, 2018-12. 13 | 14 | This document is not yet intended to be officially proposed to TC39 yet; it merely shows a possible 15 | extension of the [Core Proposal][] in the event that the Core Proposal is accepted. 16 | 17 | An additional feature – **bare constructor calls** – would make constructor calls 18 | terser. It adds a mode to bare style: if a bare-style pipeline step is preceded 19 | by a `new`, then instead of a function call, it is a constructor call. `value |> 20 | object.Constructor` is equivalent to `object.Constructor(value)`. This is 21 | backwards compatible with the [Core Proposal][] as well as all other [additional 22 | features][]. 23 | 24 | [Additional Feature BC is **formally specified in in the draft 25 | specification**][formal BC]. 26 | 27 | 28 | 29 | 30 | 34 | 35 |
With smart pipelines 31 | Status quo 32 | 33 |
36 | 37 | ```js 38 | value 39 | |> # + '!' 40 | |> new User.Message 41 | |> await stream.write(#) 42 | |> console.log; 43 | ``` 44 | 45 | 46 | 47 | ```js 48 | console.log( 49 | await stream.write( 50 | new User.Message( 51 | value + '!' 52 | ) 53 | ) 54 | ); 55 | ``` 56 | 57 |
58 | 59 | If a pipeline step starts with `new`, followed by a mere identifier, optionally 60 | with a chain of properties, and with no parentheses or brackets, then that 61 | identifier is interpreted to be a **bare constructor**. 62 | 63 | That is: **if a pipeline** is of the form\ 64 | **_topic_ `|>` `new` _identifier_**\ 65 | or **_topic_ `|>` `new` _identifier0_`.`_identifier1_**\ 66 | or **_topic_ `|>` `new` _identifier0_`.`_identifier1_`.`_identifier2_**\ 67 | or so forth,\ 68 | then the pipeline is a bare constructor call. 69 | 70 | | Valid [topic style][] | Valid [bare style][] | Invalid pipeline 71 | | ----------------------- | ---------------------------------------- | -------------------- 72 | |`… \|> new C(#)` |`… \|> new C` | `… \|> new C()` 🚫 73 | | ″″ | ″″ | `… \|> (new C)` 🚫 74 | | ″″ | ″″ | `… \|> (new C())` 🚫 75 | | ″″ | ″″ | `… \|> new (C)` 🚫 76 | | ″″ | ″″ | `… \|> new (C())` 🚫 77 | |`… \|> new o.C(#)` |`… \|> new o.C` | `… \|> new o.f()` 🚫 78 | |`… \|> new o.C(arg, #)` |`const f = $ => new o::C(arg, $); … \|> f`| `… \|> new o.C(arg)` 🚫 79 | |`… \|> new o.make()(#)` |`const C = o.make(); … \|> new C` | `… \|> new o.make()` 🚫 80 | |`… \|> new o[symbol](#)` |`const f = new o[symbol]; … \|> f` | `… \|> new o[symbol]` 🚫 81 | |`… \|> await new o.make()(#)`|`const af = new o.make(); … \|> await af`| `… \|> new await o.make()` 🚫 82 | 83 | ["data-to-ink" visual ratio]: https://www.darkhorseanalytics.com/blog/data-looks-better-naked 84 | ["don’t break my code"]: ./goals.md#dont-break-my-code 85 | ["don’t make me overthink"]: ./goals.md#dont-make-me-overthink 86 | ["don’t shoot me in the foot"]: ./goals.md#dont-shoot-me-in-the-foot 87 | ["make my code easier to read"]: ./goals.md#make-my-code-easier-to-read 88 | [`??:`]: https://github.com/tc39/proposal-nullish-coalescing/pull/23 89 | [`do` expression]: ./relations.md#do-expressions 90 | [`do` expressions]: ./relations.md#do-expressions 91 | [`for` iteration statements]: https://tc39.github.io/ecma262/#sec-iteration-statements 92 | [`in` relational operator]: https://tc39.github.io/ecma262/#sec-relational-operators 93 | [`match` expressions]: ./relations.md#pattern-matching 94 | [`new.target`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new.target 95 | [Additional Feature BA]: ./additional-feature-ba.md 96 | [Additional Feature BC]: ./additional-feature-bc.md 97 | [Additional Feature BP]: ./additional-feature-bp.md 98 | [Additional Feature NP]: ./additional-feature-np.md 99 | [Additional Feature PF]: ./additional-feature-pf.md 100 | [Additional Feature TS]: ./additional-feature-ts.md 101 | [additional features]: ./readme.md#additional-features 102 | [annevk]: https://github.com/annevk 103 | [antecedent]: https://en.wikipedia.org/wiki/Antecedent_(grammar) 104 | [arbitrary associativity]: ./goals.md#arbitrary-associativity 105 | [ASI]: https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion 106 | [associative property]: https://en.wikipedia.org/wiki/Associative_property 107 | [async pipeline functions]: ./additional-feature-pf.md 108 | [Babel plugin]: https://github.com/valtech-nyc/babel/ 109 | [Babel update summary]: https://github.com/babel/proposals/issues/29#issuecomment-372828328 110 | [background]: ./readme.md 111 | [backward compatibility]: ./goals.md#backward-compatibility 112 | [bare awaited function call]: ./core-syntax.md#bare-style 113 | [bare constructor call]: ./core-syntax.md#bare-style 114 | [bare function call]: ./core-syntax.md#bare-style 115 | [bare style]: ./core-syntax.md#bare-style 116 | [binding]: https://en.wikipedia.org/wiki/Binding_(linguistics) 117 | [block parameters]: ./relations.md#block-parameters 118 | [Clojure compact function]: https://clojure.org/reference/reader#_dispatch 119 | [Clojure pipe]: https://clojuredocs.org/clojure.core/as-%3E 120 | [completion records]: https://timothygu.me/es-howto/#completion-records-and-shorthands 121 | [concatenative programming]: https://en.wikipedia.org/wiki/Concatenative_programming_language 122 | [conceptual generality]: ./goals.md#conceptual-generality 123 | [Core Proposal]: ./readme.md 124 | [core-real-examples.md]: ./core-real-examples.md 125 | [currying]: https://en.wikipedia.org/wiki/Currying 126 | [cyclomatic complexity]: https://en.wikipedia.org/wiki/Cyclomatic_complexity#Applications 127 | [cyclomatic simplicity]: ./goals.md#cyclomatic-simplicity 128 | [dataflow programming]: https://en.wikipedia.org/wiki/Dataflow_programming 129 | [distinguishable punctuators]: ./goals.md#distinguishable-punctuators 130 | [don’t break my code]: ./goals.md#dont-break-my-code 131 | [DSLs]: https://en.wikipedia.org/wiki/Domain-specific_language 132 | [early error rule]: ./goals.md#static-analyzability 133 | [early error rules]: ./goals.md#static-analyzability 134 | [early error]: ./goals.md#static-analyzability 135 | [early errors]: ./goals.md#static-analyzability 136 | [ECMAScript _Identifier Name_]: https://tc39.github.io/ecma262/#prod-IdentifierName 137 | [ECMAScript _Identifier Reference_]: https://tc39.github.io/ecma262/#prod-IdentifierReference 138 | [ECMAScript _Member Expression_]: https://tc39.github.io/ecma262/#prod-MemberExpression 139 | [ECMAScript § The Syntactic Grammar]: https://tc39.github.io/ecma262/#sec-syntactic-grammar 140 | [ECMAScript `new` operator, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-new-operator-runtime-semantics-evaluation 141 | [ECMAScript arrow functions, § SS: Contains]: https://tc39.github.io/ecma262/#sec-arrow-function-definitions-static-semantics-contains 142 | [ECMAScript Assignment-level Expressions]: https://tc39.github.io/ecma262/#sec-assignment-operators 143 | [ECMAScript block parameters]: https://github.com/samuelgoto/proposal-block-params 144 | [ECMAScript Blocks, § RS: Block Declaration Instantiation]: https://tc39.github.io/ecma262/#sec-blockdeclarationinstantiation 145 | [ECMAScript Blocks, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-block-runtime-semantics-evaluation 146 | [ECMAScript Declarative Environment Records]: https://tc39.github.io/ecma262/#sec-declarative-environment-records 147 | [ECMAScript function binding]: https://github.com/zenparsing/es-function-bind 148 | [ECMAScript Function Calls, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-function-calls-runtime-semantics-evaluation 149 | [ECMAScript Function Environment Records]: https://tc39.github.io/ecma262/#sec-function-environment-records 150 | [ECMAScript Functions and Classes § Generator Function Definitions]: https://tc39.github.io/ecma262/#sec-generator-function-definitions 151 | [ECMAScript Get This Environment]: https://tc39.github.io/ecma262/#sec-getthisenvironment 152 | [ECMAScript headless-arrow proposal]: https://bterlson.github.io/headless-arrows/ 153 | [ECMAScript Lexical Environments]: https://tc39.github.io/ecma262/#sec-lexical-environments 154 | [ECMAScript Lexical Grammar]: https://tc39.github.io/ecma262/#sec-ecmascript-language-lexical-grammar 155 | [ECMAScript LHS expressions]: https://tc39.github.io/ecma262/#sec-left-hand-side-expressions 156 | [ECMAScript Lists and Records]: https://tc39.github.io/ecma262/#sec-list-and-record-specification-type 157 | [ECMAScript Notational Conventions, § Algorithm Conventions]: https://tc39.github.io/ecma262/#sec-algorithm-conventions-abstract-operations 158 | [ECMAScript Notational Conventions, § Grammars]: https://tc39.github.io/ecma262/#sec-syntactic-and-lexical-grammars 159 | [ECMAScript Notational Conventions, § Lexical Grammar]: https://tc39.github.io/ecma262/#sec-lexical-and-regexp-grammars 160 | [ECMAScript Notational Conventions, § Runtime Semantics]: https://tc39.github.io/ecma262/#sec-runtime-semantics 161 | [ECMAScript optional `catch` binding]: https://github.com/tc39/proposal-optional-catch-binding 162 | [ECMAScript partial application]: https://github.com/tc39/proposal-partial-application 163 | [ECMAScript pattern matching]: https://github.com/tc39/proposal-pattern-matching 164 | [ECMAScript Primary Expressions]: https://tc39.github.io/ecma262/#prod-PrimaryExpression 165 | [ECMAScript Property Accessors, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-property-accessors-runtime-semantics-evaluation 166 | [ECMAScript Punctuators]: https://tc39.github.io/ecma262/#sec-punctuators 167 | [ECMAScript static semantic rules]: https://tc39.github.io/ecma262/#sec-static-semantic-rules 168 | [Elixir pipe]: https://hexdocs.pm/elixir/Kernel.html#%7C%3E/2 169 | [Elm pipe]: http://elm-lang.org/docs/syntax#infix-operators 170 | [essential complexity]: https://en.wikipedia.org/wiki/Essential_complexity 171 | [expressions and operators (MDN)]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators 172 | [expressive versatility]: ./goals.md#expressive-versatility 173 | [F# pipe]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/functions/index#function-composition-and-pipelining 174 | [first pipe-operator proposal]: https://github.com/tc39/proposal-pipeline-operator/blob/37119110d40226476f7af302a778bc981f606cee/README.md 175 | [footguns]: https://en.wiktionary.org/wiki/footgun 176 | [formal BA]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-ba 177 | [formal BC]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-bc 178 | [formal BP]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-bp 179 | [formal CP]: https://jschoi.org/18/es-smart-pipelines/spec#introduction 180 | [formal NP]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-np 181 | [formal PF]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-pf 182 | [formal pipeline specification]: https://jschoi.org/18/es-smart-pipelines/spec 183 | [formal TS]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-ts 184 | [forward compatibility]: ./goals.md#forward-compatibility 185 | [forward compatible]: ./goals.md#forward-compatibility 186 | [function bind operator `::`]: ./relations.md#function-bind-operator 187 | [function binding]: ./relations.md#function-binding 188 | [function composition]: ./relations.md#function-composition 189 | [functional programming]: https://en.wikipedia.org/wiki/Functional_programming 190 | [gajus functional composition]: https://github.com/gajus/babel-plugin-transform-function-composition 191 | [garden-path syntax]: https://en.wikipedia.org/wiki/Garden_path_sentence 192 | [GitHub issue tracker]: https://github.com/tc39/proposal-pipeline-operator/issues 193 | [goals]: ./goals.md 194 | [Hack pipe]: https://docs.hhvm.com/hack/operators/pipe-operator 195 | [Huffman coding]: https://en.wikipedia.org/wiki/Huffman_coding 196 | [human writability]: ./goals.md#human-writability 197 | [i-am-tom functional composition]: https://github.com/fantasyland/ECMAScript-proposals/issues/1#issuecomment-306243513 198 | [identity function]: https://en.wikipedia.org/wiki/Identity_function 199 | [IIFEs]: https://en.wikipedia.org/wiki/Immediately-invoked_function_expression 200 | [immutable objects]: https://en.wikipedia.org/wiki/Immutable_object 201 | [incidental complexity]: https://en.wikipedia.org/wiki/Incidental_complexity 202 | [intro]: readme.md 203 | [isiahmeadows functional composition]: https://github.com/isiahmeadows/function-composition-proposal 204 | [jashkenas]: https://github.com/jashkenas 205 | [jQuery + CP]: ./core-real-examples.md#jquery 206 | [jQuery]: https://jquery.com/ 207 | [jquery/src/core/access.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/access.js 208 | [jquery/src/core/init.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/init.js 209 | [jquery/src/core/parseHTML.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/parseHTML.js 210 | [JS Foundation]: https://js.foundation/ 211 | [Julia pipe]: https://docs.julialang.org/en/stable/stdlib/base/#Base.:|> 212 | [lexical topic]: https://jschoi.org/18/es-smart-pipelines/spec#sec-lexical-topics 213 | [lexically hygienic]: https://en.wikipedia.org/wiki/Hygienic_macro 214 | [littledan invitation]: https://github.com/tc39/proposal-pipeline-operator/issues/89#issuecomment-363853394 215 | [littledan]: https://github.com/littledan 216 | [LiveScript pipe]: http://livescript.net/#operators-piping 217 | [Lodash + CP + BP + PF]: ./additional-feature-pf.md#lodash-core-proposal--additional-feature-bppf 218 | [Lodash + CP + BP + PP + PF + NP]: ./additional-feature-np.md#lodash-core-proposal--additional-features-bppppfmt 219 | [Lodash + CP]: ./core-real-examples.md#lodash 220 | [Lodash]: https://lodash.com/ 221 | [mAAdhaTTah]: https://github.com/mAAdhaTTah/ 222 | [make my code easier to read]: ./goals.md#make-my-code-easier-to-read 223 | [MDN operator precedence]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence 224 | [MDN operator precedence]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table 225 | [method-extraction inline caching]: https://github.com/tc39/proposal-bind-operator/issues/46 226 | [mindeavor]: https://github.com/gilbert 227 | [mode errors]: https://en.wikipedia.org/wiki/Mode_(computer_interface)#Mode_errors 228 | [motivation]: ./readme.md 229 | [Node-stream piping]: https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options 230 | [Node.js `util.promisify`]: https://nodejs.org/api/util.html#util_util_promisify_original 231 | [nomenclature]: ./nomenclature.md 232 | [novice learnability]: ./goals.md#novice-learnability 233 | [nullish coalescing proposal]: https://github.com/tc39/proposal-nullish-coalescing/ 234 | [object initializers’ Computed Property Contains rule]: https://tc39.github.io/ecma262/#sec-object-initializer-static-semantics-computedpropertycontains 235 | [OCaml pipe]: http://blog.shaynefletcher.org/2013/12/pipelining-with-operator-in-ocaml.html 236 | [operator precedence]: ./core-syntax.md#operator-precedence-and-associativity 237 | [opt-in behavior]: ./goals.md#opt-in-behavior 238 | [optional `catch` binding]: ./relations.md#optional-catch-binding 239 | [optional-chaining syntax proposal]: https://github.com/tc39/proposal-optional-chaining 240 | [other browsers’ console variables]: https://www.andismith.com/blogs/2011/11/25-dev-tool-secrets/ 241 | [other ECMAScript proposals]: ./relations.md#other-ecmascript-proposals 242 | [other goals]: ./goals.md#other-goals 243 | [pattern matching]: ./relations.md#pattern-matching 244 | [partial function application]: ./goals.md#partial-function-application 245 | [PEP 20]: https://www.python.org/dev/peps/pep-0020/ 246 | [Perl 6 pipe]: https://docs.perl6.org/language/operators#infix_==> 247 | [Perl 6 topicization]: https://www.perl.com/pub/2002/10/30/topic.html/ 248 | [Perl 6’s given block]: https://docs.perl6.org/language/control#given 249 | [pipeline functions]: ./additional-feature-pf.md 250 | [Pipeline Proposal 1]: https://github.com/tc39/proposal-pipeline-operator/wiki#proposal-1-f-sharp-only 251 | [Pipeline Proposal 4]: https://github.com/tc39/proposal-pipeline-operator/wiki#proposal-4-smart-mix 252 | [pipeline syntax]: ./core-syntax.md 253 | [pipelines]: ./readme.md 254 | [previous pipeline-placeholder discussions]: https://github.com/tc39/proposal-pipeline-operator/issues?q=placeholder 255 | [primary topic]: ./readme.md 256 | [private class fields]: https://github.com/tc39/proposal-class-fields/ 257 | [pure functions]: https://en.wikipedia.org/wiki/Pure_function 258 | [R pipe]: https://cran.r-project.org/web/packages/magrittr/vignettes/magrittr.html 259 | [Ramda + CP + BP + PF + NP]: ./additional-feature-np.md#ramda-core-proposal--additional-features-bppfmt 260 | [Ramda + CP + BP + PF]: ./additional-feature-pf.md#ramda-core-proposal--additional-feature-bppf 261 | [Ramda wiki cookbook]: https://github.com/ramda/ramda/wiki/Cookbook 262 | [Ramda]: http://ramdajs.com/ 263 | [relations to other work]: ./relations.md 264 | [REPLs]: https://en.wikipedia.org/wiki/Read–eval–print_loop 265 | [rest topic]: ./additional-feature-np.md 266 | [reverse Polish notation]: https://en.wikipedia.org/wiki/Reverse_Polish_notation 267 | [robust method extraction]: https://github.com/tc39/proposal-pipeline-operator/issues/110#issuecomment-374367888 268 | [Ron Buckton]: https://github.com/rbuckton 269 | [secondary topic]: ./additional-feature-np.md 270 | [semantic clarity]: ./goals.md#semantic-clarity 271 | [simonstaton functional composition]: https://github.com/simonstaton/Function.prototype.compose-TC39-Proposal 272 | [simple scoping]: ./goals.md#simple-scoping 273 | [sindresorhus]: https://github.com/sindresorhus 274 | [smart step syntax]: ./core-syntax.md 275 | [smart pipelines]: ./readme.md#smart-pipelines 276 | [Standard Style]: https://standardjs.com/ 277 | [static analyzability]: ./goals.md#static-analyzability 278 | [statically analyzable]: ./goals.md#static-analyzability 279 | [statically detectable early errors]: ./goals.md#static-analyzability 280 | [syntactic locality]: ./goals.md#syntactic-locality 281 | [tacit programming]: https://en.wikipedia.org/wiki/Tacit_programming 282 | [TC39 60th meeting, pipelines]: https://tc39.github.io/tc39-notes/2017-09_sep-26.html#11iia-pipeline-operator 283 | [TC39 process]: https://tc39.github.io/process-document/ 284 | [tc39/proposal-decorators#30]: tc39/proposal-decorators#30 285 | [tc39/proposal-decorators#42]: tc39/proposal-decorators#42 286 | [tc39/proposal-decorators#60]: tc39/proposal-decorators#60 287 | [Tennent correspondence principle]: http://gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html 288 | [term rewriting]: ./term-rewriting.md 289 | [terse composition]: ./goals.md#terse-composition 290 | [terse function application]: ./goals.md#terse-function-application 291 | [terse function calls]: ./goals.md#terse-function-calls 292 | [terse method extraction]: ./goals.md#terse-method-extraction 293 | [terse parentheses]: ./goals.md#terse-parentheses 294 | [terse partial application]: ./goals.md#terse-partial-application 295 | [terse variables]: ./goals.md#terse-variables 296 | [tertiary topic]: ./additional-feature-np.md 297 | [TheNavigateur functional composition]: https://github.com/TheNavigateur/proposal-pipeline-operator-for-function-composition 298 | [topic and comment]: https://en.wikipedia.org/wiki/Topic_and_comment 299 | [topic references in other programming languages]: ./relations.md#topic-references-in-other-programming-languages 300 | [topic style]: ./core-syntax.md#topic-style 301 | [topic variables in other languages]: https://rosettacode.org/wiki/Topic_variable 302 | [topic-token bikeshedding]: https://github.com/tc39/proposal-pipeline-operator/issues/91 303 | [Underscore.js + CP + BP + PP]: ./additional-feature-pp.md#underscorejs-core-proposal--additional-feature-bppp 304 | [Underscore.js + CP]: ./core-real-examples.md#underscorejs 305 | [Underscore.js]: http://underscorejs.org 306 | [Unix pipe]: https://en.wikipedia.org/wiki/Pipeline_(Unix 307 | [untangled flow]: ./goals.md#untangled-flow 308 | [Visual Basic’s `select` statement]: https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/select-case-statement 309 | [WebKit console variables]: https://webkit.org/blog/829/web-inspector-updates/ 310 | [WHATWG Fetch + CP]: ./core-real-examples.md#whatwg-fetch-standard 311 | [WHATWG Fetch Standard]: https://fetch.spec.whatwg.org/ 312 | [WHATWG Streams + CP + BP + PF + NP]: ./additional-feature-np.md#whatwg-streams-standard-core-proposal--additional-features-bppfmt 313 | [WHATWG Streams + CP + BP + PF]: ./additional-feature-pf.md#whatwg-streams-standard-core-proposal--additional-feature-bppf 314 | [WHATWG Streams Standard]: https://stream.spec.whatwg.org/ 315 | [WHATWG-stream piping]: https://streams.spec.whatwg.org/#pipe-chains 316 | [Wikipedia: term rewriting]: https://en.wikipedia.org/wiki/Term_rewriting 317 | [zero runtime cost]: ./goals.md#zero-runtime-cost 318 | -------------------------------------------------------------------------------- /additional-feature-bp.md: -------------------------------------------------------------------------------- 1 | |Name | Status | Features | Purpose | 2 | | ----------------------- | ------- | ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | 3 | |[Core Proposal][] | Stage 0 | Infix pipelines `… \|> …`
Lexical topic `#` | **Unary** function/expression **application** | 4 | |[Additional Feature BC][]| None | Bare constructor calls `… \|> new …` | Tacit application of **constructors** | 5 | |[Additional Feature BA][]| None | Bare awaited calls `… \|> await …` | Tacit application of **async functions** | 6 | |[Additional Feature BP][]| None | Block pipeline steps `… \|> {…}` | Application of **statement blocks** | 7 | |[Additional Feature PF][]| None | Pipeline functions `+> ` | **Partial** function/expression **application**
Function/expression **composition**
**Method extraction** | 8 | |[Additional Feature TS][]| None | Pipeline `try` statements | Tacit application to **caught errors** | 9 | |[Additional Feature NP][]| None | N-ary pipelines `(…, …) \|> …`
Lexical topics `##`, `###`, and `...`| **N-ary** function/expression **application** | 10 | 11 | # Additional Feature BP 12 | ECMAScript No-Stage Proposal. Living Document. J. S. Choi, 2018-12. 13 | 14 | This document is not yet intended to be officially proposed to TC39 yet; it merely shows a possible 15 | extension of the [Core Proposal][] in the event that the Core Proposal is accepted. 16 | 17 | There is a TC39 proposal for [`do` expressions][] at Stage 1. Smart pipelines do 18 | **not** require `do` expressions. However, if [`do` expressions][] also become 19 | part of JavaScript, then, as with **any** other type of expression, a pipeline 20 | step in [topic style][] may be `do` expression, as long as the `do` expression 21 | contains the topic reference `#`. The topic reference `#` is bound to the input 22 | value, the `do` expression is evaluated, then the result of the `do` block 23 | becomes the result of that pipeline step, and the lexical environment is reset – 24 | all as usual. 25 | 26 | In this manner, pipelines with `do` expressions act as a way to create a 27 | “topic-context block”, similarly to [Perl 6’s given block][]. Within this block, 28 | statements may use the topic reference may be used as an abbreviation for the 29 | same value. This can be useful for embedding side effects, `if` `else` 30 | statements, `try` statements, and `switch` statements within pipelines. 31 | They may be made even pithier with [Additional Feature BP][], explained later. 32 | 33 | [`do` expressions][] as [topic-style][topic style] pipeline steps might be so 34 | useful, in fact, that it might be worth building them into the pipe operator 35 | `|>` itself as an add-on feature. This additional feature – **block pipelines** 36 | – adds an additional [topic-style pipeline step syntax][smart step syntax], 37 | using blocks to stand for `do` expressions. 38 | 39 | [Additional Feature BP is **formally specified in in the draft 40 | specification**][formal BP]. 41 | 42 | 43 | 44 | 45 | 49 | 50 | 69 | 98 | 131 | 152 |
With smart pipelines 46 | Status quo 47 | 48 |
51 | 52 | ```js 53 | x = input 54 | |> f 55 | |> { sideEffect(); #; } 56 | |> g; 57 | ``` 58 | Side effects may easily be embedded within block pipeline steps. 59 | 60 | 61 | 62 | ```js 63 | const $ = f(input); 64 | sideEffect(); 65 | x = g($); 66 | ``` 67 | 68 |
70 | 71 | ```js 72 | x = input 73 | |> f 74 | |> { 75 | if (typeof # === 'number') 76 | # + 1; 77 | else 78 | { data: # }; 79 | } 80 | |> g; 81 | ``` 82 | `if` `else` statements may also be used within block pipeline steps, as an 83 | alternative to the ternary conditional operator `?` `:`. 84 | 85 | 86 | 87 | ```js 88 | const _1 = f(input); 89 | let _2; 90 | if (typeof $ === 'number') 91 | _2 = $ + 1; 92 | else 93 | _2 = { data: $ }; 94 | x = g(_2); 95 | ``` 96 | 97 |
99 | 100 | ```js 101 | x = input 102 | |> f 103 | |> { 104 | try { 105 | #|> JSON.parse; 106 | catch (error) { 107 | { message: error.message }; 108 | } 109 | } 110 | } 111 | |> g; 112 | ``` 113 | `try` statements would also be useful to embed in pipelines with block steps. 114 | This example becomes even pithier with [Additional Feature TS][]. 115 | 116 | 117 | 118 | ```js 119 | const _1 = f(input); 120 | let _2; 121 | try { 122 | _2 = JSON.parse(_1); 123 | catch (error) { 124 | _2 = { message: error.message }; 125 | } 126 | } 127 | x = g(_2); 128 | ``` 129 | 130 |
132 | 133 | ```js 134 | input 135 | |> await f(#, 5) 136 | |> { 137 | if (x > 20) 138 | x + 30; 139 | else 140 | x - 10; 141 | } 142 | |> g; 143 | // 🚫 Syntax Error: 144 | // Pipeline step `|> { if (…) … else … }` 145 | // binds topic but contains 146 | // no topic reference. 147 | ``` 148 | The same [early error rules][] that apply to any topic-style pipeline step apply 149 | also to topic-style steps that are `do` expressions. 150 | 151 |
153 | 154 | As with all other [additional features][], Additional Feature BP is [forward 155 | compatible][] with the [Core Proposal][]. This compatibility includes pipeline 156 | steps that are object literals, which must be parenthesized. 157 | ```js 158 | input |> f |> { x: #, y: # } |> g; 159 | input |> f |> { if (#) { x: #, y: # }; } |> g; 160 | ``` 161 | Of course, object literals do not have to be parenthesized inside blocks. 162 | 163 | 164 | 165 | ```j 166 | 167 | { 168 | const _1 = f(input); 169 | let _2; 170 | if ($) _2 = { x: $, y: $ }; 171 | g(_2); 172 | } 173 | ``` 174 | 175 |
176 | 177 | ## WHATWG Fetch Standard (Core Proposal + Additional Feature BP) 178 | Revisiting an [example above from the WHATWG Fetch Standard][WHATWG Fetch + CP] 179 | shows how human comprehensibility could be further improved with [Additional 180 | Feature BP][]. 181 | 182 | 183 | 184 | 185 | 189 | 190 | 191 | 228 |
With smart pipelines 186 | Status quo 187 | 188 |
192 | 193 | ```js 194 | 'https://pk.example/berlin-calling' 195 | |> await fetch(#, { mode: 'cors' }) 196 | |> ( 197 | #.headers.get('content-type') 198 | |> # && # 199 | .toLowerCase() 200 | .indexOf('application/json') 201 | >= 0 202 | ) 203 | ? # 204 | : throw new TypeError() 205 | |> await #.json() 206 | |> processJSON; 207 | ``` 208 | This pipeline version uses [Core Proposal][] syntax only. 209 | 210 | 211 | 212 | ```js 213 | fetch('https://pk.example/berlin-calling', 214 | { mode: 'cors' } 215 | ).then(response => { 216 | if (response.headers.get('content-type') 217 | && response.headers.get('content-type') 218 | .toLowerCase() 219 | .indexOf('application/json') >= 0 220 | ) 221 | return response.json(); 222 | else 223 | throw new TypeError(); 224 | }).then(processJSON); 225 | ``` 226 | 227 |
229 | 230 | And this pipeline version also uses [Additional Feature BP][]. This allows the 231 | use of an `if` `else` statement instead of a ternary `?` `:` expression. 232 | ```js 233 | 'https://pk.example/berlin-calling' 234 | |> await fetch(#, { mode: 'cors' }) 235 | |> { 236 | const contentTypeIsJSON = 237 | #.headers.get('content-type') 238 | |> # && # 239 | .toLowerCase() 240 | .indexOf('application/json') 241 | >= 0; 242 | if (contentTypeIsJSON) #; 243 | else throw new TypeError(); 244 | } 245 | |> await #.json() 246 | |> processJSON; 247 | ``` 248 | It also allows the judicious use of variable/constant assignment where it would 249 | make the meaning of code clearer, rather than [requiring unnecessary variables 250 | redundant with the names of functions][terse variables]. 251 | 252 | 253 | 254 | ```js 255 | fetch('https://pk.example/berlin-calling', 256 | { mode: 'cors' } 257 | ).then(response => { 258 | if (response.headers.get('content-type') 259 | && response.headers.get('content-type') 260 | .toLowerCase() 261 | .indexOf('application/json') >= 0 262 | ) 263 | return response.json(); 264 | else 265 | throw new TypeError(); 266 | }).then(processJSON); 267 | ``` 268 | 269 |
270 | 271 | ## jQuery (Core Proposal + Additional Feature BP) 272 | Revisiting the [examples above from jQuery][jQuery + CP] with [Additional 273 | Feature BP][] shows how terseness could be further improved. 274 | 275 | 276 | 277 | 278 | 282 | 283 | 306 | 333 | 371 | 412 |
With smart pipelines 279 | Status quo 280 | 281 |
284 | 285 | ```js 286 | match 287 | |> context[#] 288 | |> (this[match] |> isFunction) 289 | ? this[match](#); 290 | : this.attr(match, #); 291 | ``` 292 | This pipeline version uses [Core Proposal][] syntax. 293 | 294 | 295 | 296 | ```js 297 | if (isFunction(this[match])) { 298 | this[match](context[match]); 299 | } else 300 | this.attr(match, context[match]); 301 | } 302 | ``` 303 | From [jquery/src/core/init.js][]. 304 | 305 |
307 | 308 | ```js 309 | match 310 | |> context[#] 311 | |> { 312 | if (this[match] |> isFunction) 313 | this[match](#); 314 | else 315 | this.attr(match, #); 316 | } 317 | ``` 318 | With [Additional Feature BP][], an `if` `else` statement can be used instead of 319 | a ternary `?` `:` expression. 320 | 321 | 322 | 323 | ```js 324 | if (isFunction(this[match])) { 325 | this[match](context[match]); 326 | } else 327 | this.attr(match, context[match]); 328 | } 329 | ``` 330 | From [jquery/src/core/init.js][]. 331 | 332 |
334 | 335 | ```js 336 | // Handle HTML strings 337 | if (…) 338 | … 339 | // Handle $(expr, $(...)) 340 | else if (!# || #.jquery) 341 | return context 342 | |> # || root 343 | |> #.find(selector); 344 | // Handle $(expr, context) 345 | else 346 | return context 347 | |> this.constructor 348 | |> #.find(selector); 349 | ``` 350 | This pipeline version uses [Core Proposal][] syntax only. Note that both 351 | statements are of the form `return context |> something |> #.find(selector)`. 352 | 353 | 354 | 355 | ```js 356 | // Handle HTML strings 357 | if (…) { 358 | … 359 | // Handle $(expr, $(...)) 360 | } else if (!context || context.jquery) { 361 | return (context || root).find(selector); 362 | // Handle $(expr, context) 363 | } else { 364 | return this.constructor(context) 365 | .find(selector); 366 | } 367 | ``` 368 | From [jquery/src/core/init.js][]. 369 | 370 |
372 | 373 | ```js 374 | return context 375 | |> { 376 | // Handle HTML strings 377 | if (…) 378 | … 379 | // Handle $(expr, $(...)) 380 | else if (!# || #.jquery) 381 | # || root; 382 | // Handle $(expr, context) 383 | else 384 | #|> this.constructor; 385 | } 386 | |> #.find(selector); 387 | ``` 388 | This pipeline version uses [Additional Feature BP][]. The common phrases `return 389 | context |>` and `|> #.find(selector)` have moved out of the `if` `else if` `else`, 390 | into its own statement. The `if` `else if` `else` itself was moved into a block in 391 | the middle of the new unified pipeline. This emphasizes the unity of the common 392 | path through which content data flow in this code. 393 | 394 | 395 | 396 | ```js 397 | // Handle HTML strings 398 | if (…) { 399 | … 400 | // Handle $(expr, $(...)) 401 | } else if (!context || context.jquery) { 402 | return (context || root).find(selector); 403 | // Handle $(expr, context) 404 | } else { 405 | return this.constructor(context) 406 | .find(selector); 407 | } 408 | ``` 409 | From [jquery/src/core/init.js][]. 410 | 411 |
413 | 414 | ```js 415 | return selector |> { 416 | if (typeof # === 'string') 417 | … 418 | else if (#|> isFunction) 419 | root.ready !== undefined 420 | ? root.ready(#) 421 | : #(jQuery); 422 | else 423 | jQuery.makeArray(#, this); 424 | }; 425 | ``` 426 | This is a example from jQuery’s codebase on which pipelines would not have been 427 | worth using without [Additional Feature BP][]. 428 | 429 | 430 | 431 | ```js 432 | if (typeof selector === 'string') { 433 | … 434 | } else if (isFunction(selector)) { 435 | return root.ready !== undefined 436 | ? root.ready(selector) 437 | : selector(jQuery); 438 | } 439 | return jQuery.makeArray(selector, this); 440 | ``` 441 | From [jquery/src/core/access.js][]. 442 | 443 |
444 | 445 | ## Lodash (Core Proposal + Additional Feature BP) 446 | 447 | 448 | 449 | 450 | 454 | 455 | 487 | 520 | 546 | 574 | 602 |
With smart pipelines 451 | Status quo 452 | 453 |
456 | 457 | ```js 458 | function hashGet (key) { 459 | return this.__data__ 460 | |> nativeCreate 461 | ? (#[key] 462 | |> # === HASH_UNDEFINED 463 | ? undefined : #) 464 | : hashOwnProperty.call(#, key) 465 | ? #[key] 466 | : undefined; 467 | } 468 | ``` 469 | This pipeline version uses [Core Proposal][] syntax only. 470 | 471 | 472 | 473 | ```js 474 | function hashGet (key) { 475 | var data = this.__data__; 476 | if (nativeCreate) { 477 | var result = data[key]; 478 | return result === HASH_UNDEFINED 479 | ? undefined : result; 480 | } 481 | return hasOwnProperty.call(data, key) 482 | ? data[key] : undefined; 483 | } 484 | ``` 485 | 486 |
488 | 489 | ```js 490 | function hashGet (key) { 491 | return this.__data__ |> { 492 | if (nativeCreate) { 493 | if (#[key] === HASH_UNDEFINED) 494 | undefined; 495 | else 496 | #; 497 | } else if (hashOwnProperty.call(#, key)) 498 | #[key]; 499 | }; 500 | } 501 | ``` 502 | This pipeline version also uses [Additional Feature BP][]. 503 | 504 | 505 | 506 | ```js 507 | function hashGet (key) { 508 | var data = this.__data__; 509 | if (nativeCreate) { 510 | var result = data[key]; 511 | return result === HASH_UNDEFINED 512 | ? undefined : result; 513 | } 514 | return hasOwnProperty.call(data, key) 515 | ? data[key] : undefined; 516 | } 517 | ``` 518 | 519 |
521 | 522 | ```js 523 | function mapCacheDelete (key) { 524 | const result = key 525 | |> getMapData(this, #) 526 | |> #['delete'] 527 | |> #(key); 528 | this.size -= result ? 1 : 0; 529 | return result; 530 | } 531 | ``` 532 | This pipeline version uses [Core Proposal][] syntax only. 533 | 534 | 535 | 536 | ```js 537 | function mapCacheDelete (key) { 538 | var result = 539 | getMapData(this, key)['delete'](key); 540 | this.size -= result ? 1 : 0; 541 | return result; 542 | } 543 | ``` 544 | 545 |
547 | 548 | ```js 549 | function mapCacheDelete (key) { 550 | return key 551 | |> getMapData(this, #) 552 | |> #['delete'] 553 | |> #(key) 554 | |> { 555 | this.size -= # ? 1 : 0; 556 | #; 557 | }; 558 | } 559 | ``` 560 | This pipeline version also uses [Additional Feature BP][]. 561 | 562 | 563 | 564 | ```js 565 | function mapCacheDelete (key) { 566 | var result = 567 | getMapData(this, key)['delete'](key); 568 | this.size -= result ? 1 : 0; 569 | return result; 570 | } 571 | ``` 572 | 573 |
575 | 576 | ```js 577 | function castPath (value, object) { 578 | return value |> 579 | #|> isArray 580 | ? # 581 | : (#|> isKey(#, object)) 582 | ? [#] 583 | : #|> toString |> stringToPath; 584 | } 585 | ``` 586 | This pipeline version uses [Core Proposal][] syntax only. 587 | 588 | 589 | 590 | ```js 591 | function castPath (value, object) { 592 | if (isArray(value)) { 593 | return value; 594 | } 595 | return isKey(value, object) 596 | ? [value] 597 | : stringToPath(toString(value)); 598 | } 599 | ``` 600 | 601 |
603 | 604 | ```js 605 | function castPath (value, object) { 606 | return value |> { 607 | if (#|> isArray) 608 | #; 609 | else if (#|> isKey(#, object)) 610 | [#]; 611 | else # 612 | |> toString |> stringToPath; 613 | }; 614 | } 615 | ``` 616 | This pipeline version also uses [Additional Feature BP][]. 617 | 618 | 619 | 620 | ```js 621 | function castPath (value, object) { 622 | if (isArray(value)) { 623 | return value; 624 | } 625 | return isKey(value, object) 626 | ? [value] 627 | : stringToPath(toString(value)); 628 | } 629 | ``` 630 | 631 |
632 | 633 | ["data-to-ink" visual ratio]: https://www.darkhorseanalytics.com/blog/data-looks-better-naked 634 | ["don’t break my code"]: ./goals.md#dont-break-my-code 635 | ["don’t make me overthink"]: ./goals.md#dont-make-me-overthink 636 | ["don’t shoot me in the foot"]: ./goals.md#dont-shoot-me-in-the-foot 637 | ["make my code easier to read"]: ./goals.md#make-my-code-easier-to-read 638 | [`??:`]: https://github.com/tc39/proposal-nullish-coalescing/pull/23 639 | [`do` expression]: ./relations.md#do-expressions 640 | [`do` expressions]: ./relations.md#do-expressions 641 | [`for` iteration statements]: https://tc39.github.io/ecma262/#sec-iteration-statements 642 | [`in` relational operator]: https://tc39.github.io/ecma262/#sec-relational-operators 643 | [`match` expressions]: ./relations.md#pattern-matching 644 | [`new.target`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new.target 645 | [Additional Feature BA]: ./additional-feature-ba.md 646 | [Additional Feature BC]: ./additional-feature-bc.md 647 | [Additional Feature BP]: ./additional-feature-bp.md 648 | [Additional Feature NP]: ./additional-feature-np.md 649 | [Additional Feature PF]: ./additional-feature-pf.md 650 | [Additional Feature TS]: ./additional-feature-ts.md 651 | [additional features]: ./readme.md#additional-features 652 | [annevk]: https://github.com/annevk 653 | [antecedent]: https://en.wikipedia.org/wiki/Antecedent_(grammar) 654 | [arbitrary associativity]: ./goals.md#arbitrary-associativity 655 | [ASI]: https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion 656 | [associative property]: https://en.wikipedia.org/wiki/Associative_property 657 | [async pipeline functions]: ./additional-feature-pf.md 658 | [Babel plugin]: https://github.com/valtech-nyc/babel/ 659 | [Babel update summary]: https://github.com/babel/proposals/issues/29#issuecomment-372828328 660 | [background]: ./readme.md 661 | [backward compatibility]: ./goals.md#backward-compatibility 662 | [bare awaited function call]: ./core-syntax.md#bare-style 663 | [bare constructor call]: ./core-syntax.md#bare-style 664 | [bare function call]: ./core-syntax.md#bare-style 665 | [bare style]: ./core-syntax.md#bare-style 666 | [binding]: https://en.wikipedia.org/wiki/Binding_(linguistics) 667 | [block parameters]: ./relations.md#block-parameters 668 | [Clojure compact function]: https://clojure.org/reference/reader#_dispatch 669 | [Clojure pipe]: https://clojuredocs.org/clojure.core/as-%3E 670 | [completion records]: https://timothygu.me/es-howto/#completion-records-and-shorthands 671 | [concatenative programming]: https://en.wikipedia.org/wiki/Concatenative_programming_language 672 | [conceptual generality]: ./goals.md#conceptual-generality 673 | [Core Proposal]: ./readme.md 674 | [core-real-examples.md]: ./core-real-examples.md 675 | [currying]: https://en.wikipedia.org/wiki/Currying 676 | [cyclomatic complexity]: https://en.wikipedia.org/wiki/Cyclomatic_complexity#Applications 677 | [cyclomatic simplicity]: ./goals.md#cyclomatic-simplicity 678 | [dataflow programming]: https://en.wikipedia.org/wiki/Dataflow_programming 679 | [distinguishable punctuators]: ./goals.md#distinguishable-punctuators 680 | [don’t break my code]: ./goals.md#dont-break-my-code 681 | [DSLs]: https://en.wikipedia.org/wiki/Domain-specific_language 682 | [early error rule]: ./goals.md#static-analyzability 683 | [early error rules]: ./goals.md#static-analyzability 684 | [early error]: ./goals.md#static-analyzability 685 | [early errors]: ./goals.md#static-analyzability 686 | [ECMAScript _Identifier Name_]: https://tc39.github.io/ecma262/#prod-IdentifierName 687 | [ECMAScript _Identifier Reference_]: https://tc39.github.io/ecma262/#prod-IdentifierReference 688 | [ECMAScript _Member Expression_]: https://tc39.github.io/ecma262/#prod-MemberExpression 689 | [ECMAScript § The Syntactic Grammar]: https://tc39.github.io/ecma262/#sec-syntactic-grammar 690 | [ECMAScript `new` operator, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-new-operator-runtime-semantics-evaluation 691 | [ECMAScript arrow functions, § SS: Contains]: https://tc39.github.io/ecma262/#sec-arrow-function-definitions-static-semantics-contains 692 | [ECMAScript Assignment-level Expressions]: https://tc39.github.io/ecma262/#sec-assignment-operators 693 | [ECMAScript block parameters]: https://github.com/samuelgoto/proposal-block-params 694 | [ECMAScript Blocks, § RS: Block Declaration Instantiation]: https://tc39.github.io/ecma262/#sec-blockdeclarationinstantiation 695 | [ECMAScript Blocks, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-block-runtime-semantics-evaluation 696 | [ECMAScript Declarative Environment Records]: https://tc39.github.io/ecma262/#sec-declarative-environment-records 697 | [ECMAScript function binding]: https://github.com/zenparsing/es-function-bind 698 | [ECMAScript Function Calls, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-function-calls-runtime-semantics-evaluation 699 | [ECMAScript Function Environment Records]: https://tc39.github.io/ecma262/#sec-function-environment-records 700 | [ECMAScript Functions and Classes § Generator Function Definitions]: https://tc39.github.io/ecma262/#sec-generator-function-definitions 701 | [ECMAScript Get This Environment]: https://tc39.github.io/ecma262/#sec-getthisenvironment 702 | [ECMAScript headless-arrow proposal]: https://bterlson.github.io/headless-arrows/ 703 | [ECMAScript Lexical Environments]: https://tc39.github.io/ecma262/#sec-lexical-environments 704 | [ECMAScript Lexical Grammar]: https://tc39.github.io/ecma262/#sec-ecmascript-language-lexical-grammar 705 | [ECMAScript LHS expressions]: https://tc39.github.io/ecma262/#sec-left-hand-side-expressions 706 | [ECMAScript Lists and Records]: https://tc39.github.io/ecma262/#sec-list-and-record-specification-type 707 | [ECMAScript Notational Conventions, § Algorithm Conventions]: https://tc39.github.io/ecma262/#sec-algorithm-conventions-abstract-operations 708 | [ECMAScript Notational Conventions, § Grammars]: https://tc39.github.io/ecma262/#sec-syntactic-and-lexical-grammars 709 | [ECMAScript Notational Conventions, § Lexical Grammar]: https://tc39.github.io/ecma262/#sec-lexical-and-regexp-grammars 710 | [ECMAScript Notational Conventions, § Runtime Semantics]: https://tc39.github.io/ecma262/#sec-runtime-semantics 711 | [ECMAScript optional `catch` binding]: https://github.com/tc39/proposal-optional-catch-binding 712 | [ECMAScript partial application]: https://github.com/tc39/proposal-partial-application 713 | [ECMAScript pattern matching]: https://github.com/tc39/proposal-pattern-matching 714 | [ECMAScript Primary Expressions]: https://tc39.github.io/ecma262/#prod-PrimaryExpression 715 | [ECMAScript Property Accessors, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-property-accessors-runtime-semantics-evaluation 716 | [ECMAScript Punctuators]: https://tc39.github.io/ecma262/#sec-punctuators 717 | [ECMAScript static semantic rules]: https://tc39.github.io/ecma262/#sec-static-semantic-rules 718 | [Elixir pipe]: https://hexdocs.pm/elixir/Kernel.html#%7C%3E/2 719 | [Elm pipe]: http://elm-lang.org/docs/syntax#infix-operators 720 | [essential complexity]: https://en.wikipedia.org/wiki/Essential_complexity 721 | [expressions and operators (MDN)]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators 722 | [expressive versatility]: ./goals.md#expressive-versatility 723 | [F# pipe]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/functions/index#function-composition-and-pipelining 724 | [first pipe-operator proposal]: https://github.com/tc39/proposal-pipeline-operator/blob/37119110d40226476f7af302a778bc981f606cee/README.md 725 | [footguns]: https://en.wiktionary.org/wiki/footgun 726 | [formal BA]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-ba 727 | [formal BC]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-bc 728 | [formal BP]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-bp 729 | [formal CP]: https://jschoi.org/18/es-smart-pipelines/spec#introduction 730 | [formal NP]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-np 731 | [formal PF]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-pf 732 | [formal pipeline specification]: https://jschoi.org/18/es-smart-pipelines/spec 733 | [formal TS]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-ts 734 | [forward compatibility]: ./goals.md#forward-compatibility 735 | [forward compatible]: ./goals.md#forward-compatibility 736 | [function bind operator `::`]: ./relations.md#function-bind-operator 737 | [function binding]: ./relations.md#function-binding 738 | [function composition]: ./relations.md#function-composition 739 | [functional programming]: https://en.wikipedia.org/wiki/Functional_programming 740 | [gajus functional composition]: https://github.com/gajus/babel-plugin-transform-function-composition 741 | [garden-path syntax]: https://en.wikipedia.org/wiki/Garden_path_sentence 742 | [GitHub issue tracker]: https://github.com/tc39/proposal-pipeline-operator/issues 743 | [goals]: ./goals.md 744 | [Hack pipe]: https://docs.hhvm.com/hack/operators/pipe-operator 745 | [Huffman coding]: https://en.wikipedia.org/wiki/Huffman_coding 746 | [human writability]: ./goals.md#human-writability 747 | [i-am-tom functional composition]: https://github.com/fantasyland/ECMAScript-proposals/issues/1#issuecomment-306243513 748 | [identity function]: https://en.wikipedia.org/wiki/Identity_function 749 | [IIFEs]: https://en.wikipedia.org/wiki/Immediately-invoked_function_expression 750 | [immutable objects]: https://en.wikipedia.org/wiki/Immutable_object 751 | [incidental complexity]: https://en.wikipedia.org/wiki/Incidental_complexity 752 | [intro]: readme.md 753 | [isiahmeadows functional composition]: https://github.com/isiahmeadows/function-composition-proposal 754 | [jashkenas]: https://github.com/jashkenas 755 | [jQuery + CP]: ./core-real-examples.md#jquery 756 | [jQuery]: https://jquery.com/ 757 | [jquery/src/core/access.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/access.js 758 | [jquery/src/core/init.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/init.js 759 | [jquery/src/core/parseHTML.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/parseHTML.js 760 | [JS Foundation]: https://js.foundation/ 761 | [Julia pipe]: https://docs.julialang.org/en/stable/stdlib/base/#Base.:|> 762 | [lexical topic]: https://jschoi.org/18/es-smart-pipelines/spec#sec-lexical-topics 763 | [lexically hygienic]: https://en.wikipedia.org/wiki/Hygienic_macro 764 | [littledan invitation]: https://github.com/tc39/proposal-pipeline-operator/issues/89#issuecomment-363853394 765 | [littledan]: https://github.com/littledan 766 | [LiveScript pipe]: http://livescript.net/#operators-piping 767 | [Lodash + CP + BP + PF]: ./additional-feature-pf.md#lodash-core-proposal--additional-feature-bppf 768 | [Lodash + CP + BP + PP + PF + NP]: ./additional-feature-np.md#lodash-core-proposal--additional-features-bppppfmt 769 | [Lodash + CP]: ./core-real-examples.md#lodash 770 | [Lodash]: https://lodash.com/ 771 | [mAAdhaTTah]: https://github.com/mAAdhaTTah/ 772 | [make my code easier to read]: ./goals.md#make-my-code-easier-to-read 773 | [MDN operator precedence]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence 774 | [MDN operator precedence]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table 775 | [method-extraction inline caching]: https://github.com/tc39/proposal-bind-operator/issues/46 776 | [mindeavor]: https://github.com/gilbert 777 | [mode errors]: https://en.wikipedia.org/wiki/Mode_(computer_interface)#Mode_errors 778 | [motivation]: ./readme.md 779 | [Node-stream piping]: https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options 780 | [Node.js `util.promisify`]: https://nodejs.org/api/util.html#util_util_promisify_original 781 | [nomenclature]: ./nomenclature.md 782 | [novice learnability]: ./goals.md#novice-learnability 783 | [nullish coalescing proposal]: https://github.com/tc39/proposal-nullish-coalescing/ 784 | [object initializers’ Computed Property Contains rule]: https://tc39.github.io/ecma262/#sec-object-initializer-static-semantics-computedpropertycontains 785 | [OCaml pipe]: http://blog.shaynefletcher.org/2013/12/pipelining-with-operator-in-ocaml.html 786 | [operator precedence]: ./core-syntax.md#operator-precedence-and-associativity 787 | [opt-in behavior]: ./goals.md#opt-in-behavior 788 | [optional `catch` binding]: ./relations.md#optional-catch-binding 789 | [optional-chaining syntax proposal]: https://github.com/tc39/proposal-optional-chaining 790 | [other browsers’ console variables]: https://www.andismith.com/blogs/2011/11/25-dev-tool-secrets/ 791 | [other ECMAScript proposals]: ./relations.md#other-ecmascript-proposals 792 | [other goals]: ./goals.md#other-goals 793 | [pattern matching]: ./relations.md#pattern-matching 794 | [partial function application]: ./goals.md#partial-function-application 795 | [PEP 20]: https://www.python.org/dev/peps/pep-0020/ 796 | [Perl 6 pipe]: https://docs.perl6.org/language/operators#infix_==> 797 | [Perl 6 topicization]: https://www.perl.com/pub/2002/10/30/topic.html/ 798 | [Perl 6’s given block]: https://docs.perl6.org/language/control#given 799 | [pipeline functions]: ./additional-feature-pf.md 800 | [Pipeline Proposal 1]: https://github.com/tc39/proposal-pipeline-operator/wiki#proposal-1-f-sharp-only 801 | [Pipeline Proposal 4]: https://github.com/tc39/proposal-pipeline-operator/wiki#proposal-4-smart-mix 802 | [pipeline syntax]: ./core-syntax.md 803 | [pipelines]: ./readme.md 804 | [previous pipeline-placeholder discussions]: https://github.com/tc39/proposal-pipeline-operator/issues?q=placeholder 805 | [primary topic]: ./readme.md 806 | [private class fields]: https://github.com/tc39/proposal-class-fields/ 807 | [pure functions]: https://en.wikipedia.org/wiki/Pure_function 808 | [R pipe]: https://cran.r-project.org/web/packages/magrittr/vignettes/magrittr.html 809 | [Ramda + CP + BP + PF + NP]: ./additional-feature-np.md#ramda-core-proposal--additional-features-bppfmt 810 | [Ramda + CP + BP + PF]: ./additional-feature-pf.md#ramda-core-proposal--additional-feature-bppf 811 | [Ramda wiki cookbook]: https://github.com/ramda/ramda/wiki/Cookbook 812 | [Ramda]: http://ramdajs.com/ 813 | [relations to other work]: ./relations.md 814 | [REPLs]: https://en.wikipedia.org/wiki/Read–eval–print_loop 815 | [rest topic]: ./additional-feature-np.md 816 | [reverse Polish notation]: https://en.wikipedia.org/wiki/Reverse_Polish_notation 817 | [robust method extraction]: https://github.com/tc39/proposal-pipeline-operator/issues/110#issuecomment-374367888 818 | [Ron Buckton]: https://github.com/rbuckton 819 | [secondary topic]: ./additional-feature-np.md 820 | [semantic clarity]: ./goals.md#semantic-clarity 821 | [simonstaton functional composition]: https://github.com/simonstaton/Function.prototype.compose-TC39-Proposal 822 | [simple scoping]: ./goals.md#simple-scoping 823 | [sindresorhus]: https://github.com/sindresorhus 824 | [smart step syntax]: ./core-syntax.md 825 | [smart pipelines]: ./readme.md#smart-pipelines 826 | [Standard Style]: https://standardjs.com/ 827 | [static analyzability]: ./goals.md#static-analyzability 828 | [statically analyzable]: ./goals.md#static-analyzability 829 | [statically detectable early errors]: ./goals.md#static-analyzability 830 | [syntactic locality]: ./goals.md#syntactic-locality 831 | [tacit programming]: https://en.wikipedia.org/wiki/Tacit_programming 832 | [TC39 60th meeting, pipelines]: https://tc39.github.io/tc39-notes/2017-09_sep-26.html#11iia-pipeline-operator 833 | [TC39 process]: https://tc39.github.io/process-document/ 834 | [tc39/proposal-decorators#30]: tc39/proposal-decorators#30 835 | [tc39/proposal-decorators#42]: tc39/proposal-decorators#42 836 | [tc39/proposal-decorators#60]: tc39/proposal-decorators#60 837 | [Tennent correspondence principle]: http://gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html 838 | [term rewriting]: ./term-rewriting.md 839 | [terse composition]: ./goals.md#terse-composition 840 | [terse function application]: ./goals.md#terse-function-application 841 | [terse function calls]: ./goals.md#terse-function-calls 842 | [terse method extraction]: ./goals.md#terse-method-extraction 843 | [terse parentheses]: ./goals.md#terse-parentheses 844 | [terse partial application]: ./goals.md#terse-partial-application 845 | [terse variables]: ./goals.md#terse-variables 846 | [tertiary topic]: ./additional-feature-np.md 847 | [TheNavigateur functional composition]: https://github.com/TheNavigateur/proposal-pipeline-operator-for-function-composition 848 | [topic and comment]: https://en.wikipedia.org/wiki/Topic_and_comment 849 | [topic references in other programming languages]: ./relations.md#topic-references-in-other-programming-languages 850 | [topic style]: ./core-syntax.md#topic-style 851 | [topic variables in other languages]: https://rosettacode.org/wiki/Topic_variable 852 | [topic-token bikeshedding]: https://github.com/tc39/proposal-pipeline-operator/issues/91 853 | [Underscore.js + CP + BP + PP]: ./additional-feature-pp.md#underscorejs-core-proposal--additional-feature-bppp 854 | [Underscore.js + CP]: ./core-real-examples.md#underscorejs 855 | [Underscore.js]: http://underscorejs.org 856 | [Unix pipe]: https://en.wikipedia.org/wiki/Pipeline_(Unix 857 | [untangled flow]: ./goals.md#untangled-flow 858 | [Visual Basic’s `select` statement]: https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/select-case-statement 859 | [WebKit console variables]: https://webkit.org/blog/829/web-inspector-updates/ 860 | [WHATWG Fetch + CP]: ./core-real-examples.md#whatwg-fetch-standard 861 | [WHATWG Fetch Standard]: https://fetch.spec.whatwg.org/ 862 | [WHATWG Streams + CP + BP + PF + NP]: ./additional-feature-np.md#whatwg-streams-standard-core-proposal--additional-features-bppfmt 863 | [WHATWG Streams + CP + BP + PF]: ./additional-feature-pf.md#whatwg-streams-standard-core-proposal--additional-feature-bppf 864 | [WHATWG Streams Standard]: https://stream.spec.whatwg.org/ 865 | [WHATWG-stream piping]: https://streams.spec.whatwg.org/#pipe-chains 866 | [Wikipedia: term rewriting]: https://en.wikipedia.org/wiki/Term_rewriting 867 | [zero runtime cost]: ./goals.md#zero-runtime-cost 868 | -------------------------------------------------------------------------------- /additional-feature-ts.md: -------------------------------------------------------------------------------- 1 | |Name | Status | Features | Purpose | 2 | | ----------------------- | ------- | ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | 3 | |[Core Proposal][] | Stage 0 | Infix pipelines `… \|> …`
Lexical topic `#` | **Unary** function/expression **application** | 4 | |[Additional Feature BC][]| None | Bare constructor calls `… \|> new …` | Tacit application of **constructors** | 5 | |[Additional Feature BA][]| None | Bare awaited calls `… \|> await …` | Tacit application of **async functions** | 6 | |[Additional Feature BP][]| None | Block pipeline steps `… \|> {…}` | Application of **statement blocks** | 7 | |[Additional Feature PF][]| None | Pipeline functions `+> ` | **Partial** function/expression **application**
Function/expression **composition**
**Method extraction** | 8 | |[Additional Feature TS][]| None | Pipeline `try` statements | Tacit application to **caught errors** | 9 | |[Additional Feature NP][]| None | N-ary pipelines `(…, …) \|> …`
Lexical topics `##`, `###`, and `...`| **N-ary** function/expression **application** | 10 | 11 | # Additional Feature TS 12 | ECMAScript No-Stage Proposal. Living Document. J. S. Choi, 2018-12. 13 | 14 | This document is not yet intended to be officially proposed to TC39 yet; it merely shows a possible 15 | extension of the [Core Proposal][] in the event that the Core Proposal is accepted. 16 | 17 | With the [Core Proposal][] only, all `try` statements’ `catch` clauses would 18 | prohibit the use of the topic reference within their steps, except where the 19 | topic reference `#` is inside an inner pipeline inside the `catch` clause: this 20 | is one of the Core Proposal’s [early errors][] mentioned above. 21 | 22 | This additional feature – **Pipeline `try` Statements** – would add new forms of 23 | the `try` statement, the `catch` clause, and the `finally` clause, in the form 24 | of `try |> …`, `catch |> …`, and `finally |> …`, each followed by a [pipeline 25 | with the same smart step syntax][smart step syntax]. 26 | 27 | The developer must **[opt into this behavior][opt-in behavior]** by using a 28 | pipeline token `|>`, followed by the pipeline. No existing code would be 29 | affected. Any, some, or none of the three clauses in a `try` statement may be in 30 | a pipeline form versus the regular block form. 31 | 32 | A pipeline `try |> …` statement or a `finally |> …` clause would apply the outer 33 | context’s topic to their pipelines. As usual, it would be an [early error][] if 34 | the outer context has no topic binding. 35 | 36 | A pipeline `catch |> …` clause would treat its caught error as if it were the 37 | pipeline’s head value. 38 | 39 | With [Additional Feature BP][], this syntax which would naturally allow the form 40 | `catch |> { … }`, except, within the block, the error would be `#`. 41 | 42 | In addition, a bare `catch` form, completely lacking a parenthesized antecedent, 43 | has already been proposed as [optional `catch` binding][]. This bare form is 44 | mutually compatible with Additional Feature TS. 45 | 46 | [Additional Feature TS is **formally specified in in the draft 47 | specification**][formal TS]. 48 | 49 | 50 | 51 | 52 | 56 | 57 | 94 | 122 | 153 | 187 | 214 | 237 |
With smart pipelines 53 | Status quo 54 | 55 |
58 | 59 | The example below also uses [Additional Feature BP][]. 60 | 61 | The `try` clause is in the pipeline form using the [topic style][]. It applies 62 | the expression `1 / #` to the outer context’s topic (in this case, `f(value)`). 63 | 64 | The `catch` clause is also in the pipeline form using the [bare style][]. It 65 | applies the function `processError` to the caught error. 66 | 67 | ```js 68 | value 69 | |> f 70 | |> { 71 | try |> 1 / #; 72 | catch |> processError; 73 | } 74 | |> g; 75 | ``` 76 | The semicolons after `1 / #` and after `processError` are optional. There is no 77 | ASI hazard here because pipeline steps may never contain a `catch` or `finally` 78 | clause, unless the clause is inside a block. 79 | 80 | 81 | 82 | ```js 83 | let _1; 84 | try { 85 | _1 = 1 / f(value); 86 | } 87 | catch (error) { 88 | _1 = processError(error); 89 | } 90 | g (_1, 1); 91 | ``` 92 | 93 |
95 | 96 | ```js 97 | value 98 | |> f 99 | |> { 100 | try |> 1 / #; 101 | catch |> #.message; 102 | } 103 | |> g(#, 1); 104 | ``` 105 | Now the `catch` clause is also in topic style, applying apply `console.error` as 106 | a method call to the caught error. 107 | 108 | 109 | 110 | ```js 111 | let _1; 112 | try { 113 | _1 = 1 / f(value); 114 | } 115 | catch (error) { 116 | _1 = error.message; 117 | } 118 | g (_1, 1); 119 | ``` 120 | 121 |
123 | 124 | ```js 125 | value 126 | |> f 127 | |> { 128 | try 129 | |> 1 / #; 130 | catch 131 | |> #.message |> capitalize; 132 | } 133 | |> g(#, 1); 134 | ``` 135 | Pipeline `try` statements and their clauses may be chained as usual. This 136 | pipeline `catch` clause is in [topic style][] (`|> #.message`) followed by [bare 137 | style][] (`|> capitalize`). 138 | 139 | 140 | 141 | ```js 142 | let _1; 143 | try { 144 | _1 = 1 / f(value); 145 | } 146 | catch (error) { 147 | _1 = capitalize(error.message); 148 | } 149 | g (_1, 1); 150 | ``` 151 | 152 |
154 | 155 | This pipeline `try` statement’s `catch` clause is using the topic-block style 156 | from [Additional Feature BP][]. 157 | ```js 158 | value 159 | |> f 160 | |> { 161 | try |> 1 / #; 162 | catch |> { 163 | #.message |> capitalize; 164 | } 165 | } 166 | |> g; 167 | ``` 168 | A `|>` between `try` and its block `{ |> 1 / # }` is unnecessary, because the 169 | outer topic does not need to be rebound. However, it is necessary between 170 | `catch` and its block in order to opt into binding the topic reference to the 171 | caught errors. 172 | 173 | 174 | 175 | ```js 176 | let _1; 177 | try { 178 | _1 = 1 / f(value); 179 | } 180 | catch (error) { 181 | _1 = capitalize(error.message); 182 | } 183 | g (_1, 1); 184 | ``` 185 | 186 |
188 | 189 | If the developer includes the parenthesized parameter (like `(error)` in this 190 | example) or if they leave out the `|>` after the `catch`, then no topic binding 191 | is established. As per the [early error rules][] in [Core Proposal][], topic 192 | references are not allowed in regular `catch` blocks. 193 | ```js 194 | value 195 | |> f 196 | |> { 197 | try { 1 / #; } 198 | catch (error) { 199 | #.message |> capitalize; 200 | } 201 | } 202 | |> g(#, 1); 203 | // 🚫 Syntax Error: 204 | // Lexical context `catch { … }` 205 | // contains a topic reference 206 | // but has no topic binding. 207 | ``` 208 | This sort of [opt-in behavior][] is a goal of this proposal and helps ensure 209 | that the developer does not [shoot themselves in the foot][“don’t shoot me in 210 | the foot”] by accidentally using the topic value from an unexpected outer 211 | environment. 212 | 213 |
215 | 216 | ```js 217 | value 218 | |> f 219 | |> { 220 | try { 1 / #; } 221 | catch { 222 | #.message |> capitalize; 223 | } 224 | } 225 | |> g(#, 1); 226 | // 🚫 Syntax Error: 227 | // Lexical context `catch { … }` 228 | // contains a topic reference 229 | // but has no topic binding. 230 | ``` 231 | This opt-in behavior is mutually compatible with the proposal for [optional 232 | `catch` binding][]. 233 | 234 | 235 | 236 |
238 | 239 | ```js 240 | value 241 | |> f 242 | |> { 243 | try |> JSON.parse; 244 | catch |> { message: #.message }; 245 | } 246 | |> g(#, 1); 247 | ``` 248 | 249 | 250 | 251 | ```js 252 | let _1; 253 | try { 254 | _1 = 1 / f(value); 255 | } 256 | catch (error) { 257 | _1 = { message: error.message }; 258 | } 259 | g (_1, 1); 260 | ``` 261 | 262 |
263 | 264 | ["data-to-ink" visual ratio]: https://www.darkhorseanalytics.com/blog/data-looks-better-naked 265 | ["don’t break my code"]: ./goals.md#dont-break-my-code 266 | ["don’t make me overthink"]: ./goals.md#dont-make-me-overthink 267 | ["don’t shoot me in the foot"]: ./goals.md#dont-shoot-me-in-the-foot 268 | ["make my code easier to read"]: ./goals.md#make-my-code-easier-to-read 269 | [`??:`]: https://github.com/tc39/proposal-nullish-coalescing/pull/23 270 | [`do` expression]: ./relations.md#do-expressions 271 | [`do` expressions]: ./relations.md#do-expressions 272 | [`for` iteration statements]: https://tc39.github.io/ecma262/#sec-iteration-statements 273 | [`in` relational operator]: https://tc39.github.io/ecma262/#sec-relational-operators 274 | [`match` expressions]: ./relations.md#pattern-matching 275 | [`new.target`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new.target 276 | [Additional Feature BA]: ./additional-feature-ba.md 277 | [Additional Feature BC]: ./additional-feature-bc.md 278 | [Additional Feature BP]: ./additional-feature-bp.md 279 | [Additional Feature NP]: ./additional-feature-np.md 280 | [Additional Feature PF]: ./additional-feature-pf.md 281 | [Additional Feature TS]: ./additional-feature-ts.md 282 | [additional features]: ./readme.md#additional-features 283 | [annevk]: https://github.com/annevk 284 | [antecedent]: https://en.wikipedia.org/wiki/Antecedent_(grammar) 285 | [arbitrary associativity]: ./goals.md#arbitrary-associativity 286 | [ASI]: https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion 287 | [associative property]: https://en.wikipedia.org/wiki/Associative_property 288 | [async pipeline functions]: ./additional-feature-pf.md 289 | [Babel plugin]: https://github.com/valtech-nyc/babel/ 290 | [Babel update summary]: https://github.com/babel/proposals/issues/29#issuecomment-372828328 291 | [background]: ./readme.md 292 | [backward compatibility]: ./goals.md#backward-compatibility 293 | [bare awaited function call]: ./core-syntax.md#bare-style 294 | [bare constructor call]: ./core-syntax.md#bare-style 295 | [bare function call]: ./core-syntax.md#bare-style 296 | [bare style]: ./core-syntax.md#bare-style 297 | [binding]: https://en.wikipedia.org/wiki/Binding_(linguistics) 298 | [block parameters]: ./relations.md#block-parameters 299 | [Clojure compact function]: https://clojure.org/reference/reader#_dispatch 300 | [Clojure pipe]: https://clojuredocs.org/clojure.core/as-%3E 301 | [completion records]: https://timothygu.me/es-howto/#completion-records-and-shorthands 302 | [concatenative programming]: https://en.wikipedia.org/wiki/Concatenative_programming_language 303 | [conceptual generality]: ./goals.md#conceptual-generality 304 | [Core Proposal]: ./readme.md 305 | [core-real-examples.md]: ./core-real-examples.md 306 | [currying]: https://en.wikipedia.org/wiki/Currying 307 | [cyclomatic complexity]: https://en.wikipedia.org/wiki/Cyclomatic_complexity#Applications 308 | [cyclomatic simplicity]: ./goals.md#cyclomatic-simplicity 309 | [dataflow programming]: https://en.wikipedia.org/wiki/Dataflow_programming 310 | [distinguishable punctuators]: ./goals.md#distinguishable-punctuators 311 | [don’t break my code]: ./goals.md#dont-break-my-code 312 | [DSLs]: https://en.wikipedia.org/wiki/Domain-specific_language 313 | [early error rule]: ./goals.md#static-analyzability 314 | [early error rules]: ./goals.md#static-analyzability 315 | [early error]: ./goals.md#static-analyzability 316 | [early errors]: ./goals.md#static-analyzability 317 | [ECMAScript _Identifier Name_]: https://tc39.github.io/ecma262/#prod-IdentifierName 318 | [ECMAScript _Identifier Reference_]: https://tc39.github.io/ecma262/#prod-IdentifierReference 319 | [ECMAScript _Member Expression_]: https://tc39.github.io/ecma262/#prod-MemberExpression 320 | [ECMAScript § The Syntactic Grammar]: https://tc39.github.io/ecma262/#sec-syntactic-grammar 321 | [ECMAScript `new` operator, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-new-operator-runtime-semantics-evaluation 322 | [ECMAScript arrow functions, § SS: Contains]: https://tc39.github.io/ecma262/#sec-arrow-function-definitions-static-semantics-contains 323 | [ECMAScript Assignment-level Expressions]: https://tc39.github.io/ecma262/#sec-assignment-operators 324 | [ECMAScript block parameters]: https://github.com/samuelgoto/proposal-block-params 325 | [ECMAScript Blocks, § RS: Block Declaration Instantiation]: https://tc39.github.io/ecma262/#sec-blockdeclarationinstantiation 326 | [ECMAScript Blocks, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-block-runtime-semantics-evaluation 327 | [ECMAScript Declarative Environment Records]: https://tc39.github.io/ecma262/#sec-declarative-environment-records 328 | [ECMAScript function binding]: https://github.com/zenparsing/es-function-bind 329 | [ECMAScript Function Calls, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-function-calls-runtime-semantics-evaluation 330 | [ECMAScript Function Environment Records]: https://tc39.github.io/ecma262/#sec-function-environment-records 331 | [ECMAScript Functions and Classes § Generator Function Definitions]: https://tc39.github.io/ecma262/#sec-generator-function-definitions 332 | [ECMAScript Get This Environment]: https://tc39.github.io/ecma262/#sec-getthisenvironment 333 | [ECMAScript headless-arrow proposal]: https://bterlson.github.io/headless-arrows/ 334 | [ECMAScript Lexical Environments]: https://tc39.github.io/ecma262/#sec-lexical-environments 335 | [ECMAScript Lexical Grammar]: https://tc39.github.io/ecma262/#sec-ecmascript-language-lexical-grammar 336 | [ECMAScript LHS expressions]: https://tc39.github.io/ecma262/#sec-left-hand-side-expressions 337 | [ECMAScript Lists and Records]: https://tc39.github.io/ecma262/#sec-list-and-record-specification-type 338 | [ECMAScript Notational Conventions, § Algorithm Conventions]: https://tc39.github.io/ecma262/#sec-algorithm-conventions-abstract-operations 339 | [ECMAScript Notational Conventions, § Grammars]: https://tc39.github.io/ecma262/#sec-syntactic-and-lexical-grammars 340 | [ECMAScript Notational Conventions, § Lexical Grammar]: https://tc39.github.io/ecma262/#sec-lexical-and-regexp-grammars 341 | [ECMAScript Notational Conventions, § Runtime Semantics]: https://tc39.github.io/ecma262/#sec-runtime-semantics 342 | [ECMAScript optional `catch` binding]: https://github.com/tc39/proposal-optional-catch-binding 343 | [ECMAScript partial application]: https://github.com/tc39/proposal-partial-application 344 | [ECMAScript pattern matching]: https://github.com/tc39/proposal-pattern-matching 345 | [ECMAScript Primary Expressions]: https://tc39.github.io/ecma262/#prod-PrimaryExpression 346 | [ECMAScript Property Accessors, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-property-accessors-runtime-semantics-evaluation 347 | [ECMAScript Punctuators]: https://tc39.github.io/ecma262/#sec-punctuators 348 | [ECMAScript static semantic rules]: https://tc39.github.io/ecma262/#sec-static-semantic-rules 349 | [Elixir pipe]: https://hexdocs.pm/elixir/Kernel.html#%7C%3E/2 350 | [Elm pipe]: http://elm-lang.org/docs/syntax#infix-operators 351 | [essential complexity]: https://en.wikipedia.org/wiki/Essential_complexity 352 | [expressions and operators (MDN)]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators 353 | [expressive versatility]: ./goals.md#expressive-versatility 354 | [F# pipe]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/functions/index#function-composition-and-pipelining 355 | [first pipe-operator proposal]: https://github.com/tc39/proposal-pipeline-operator/blob/37119110d40226476f7af302a778bc981f606cee/README.md 356 | [footguns]: https://en.wiktionary.org/wiki/footgun 357 | [formal BA]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-ba 358 | [formal BC]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-bc 359 | [formal BP]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-bp 360 | [formal CP]: https://jschoi.org/18/es-smart-pipelines/spec#introduction 361 | [formal NP]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-np 362 | [formal PF]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-pf 363 | [formal pipeline specification]: https://jschoi.org/18/es-smart-pipelines/spec 364 | [formal TS]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-ts 365 | [forward compatibility]: ./goals.md#forward-compatibility 366 | [forward compatible]: ./goals.md#forward-compatibility 367 | [function bind operator `::`]: ./relations.md#function-bind-operator 368 | [function binding]: ./relations.md#function-binding 369 | [function composition]: ./relations.md#function-composition 370 | [functional programming]: https://en.wikipedia.org/wiki/Functional_programming 371 | [gajus functional composition]: https://github.com/gajus/babel-plugin-transform-function-composition 372 | [garden-path syntax]: https://en.wikipedia.org/wiki/Garden_path_sentence 373 | [GitHub issue tracker]: https://github.com/tc39/proposal-pipeline-operator/issues 374 | [goals]: ./goals.md 375 | [Hack pipe]: https://docs.hhvm.com/hack/operators/pipe-operator 376 | [Huffman coding]: https://en.wikipedia.org/wiki/Huffman_coding 377 | [human writability]: ./goals.md#human-writability 378 | [i-am-tom functional composition]: https://github.com/fantasyland/ECMAScript-proposals/issues/1#issuecomment-306243513 379 | [identity function]: https://en.wikipedia.org/wiki/Identity_function 380 | [IIFEs]: https://en.wikipedia.org/wiki/Immediately-invoked_function_expression 381 | [immutable objects]: https://en.wikipedia.org/wiki/Immutable_object 382 | [incidental complexity]: https://en.wikipedia.org/wiki/Incidental_complexity 383 | [intro]: readme.md 384 | [isiahmeadows functional composition]: https://github.com/isiahmeadows/function-composition-proposal 385 | [jashkenas]: https://github.com/jashkenas 386 | [jQuery + CP]: ./core-real-examples.md#jquery 387 | [jQuery]: https://jquery.com/ 388 | [jquery/src/core/access.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/access.js 389 | [jquery/src/core/init.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/init.js 390 | [jquery/src/core/parseHTML.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/parseHTML.js 391 | [JS Foundation]: https://js.foundation/ 392 | [Julia pipe]: https://docs.julialang.org/en/stable/stdlib/base/#Base.:|> 393 | [lexical topic]: https://jschoi.org/18/es-smart-pipelines/spec#sec-lexical-topics 394 | [lexically hygienic]: https://en.wikipedia.org/wiki/Hygienic_macro 395 | [littledan invitation]: https://github.com/tc39/proposal-pipeline-operator/issues/89#issuecomment-363853394 396 | [littledan]: https://github.com/littledan 397 | [LiveScript pipe]: http://livescript.net/#operators-piping 398 | [Lodash + CP + BP + PF]: ./additional-feature-pf.md#lodash-core-proposal--additional-feature-bppf 399 | [Lodash + CP + BP + PP + PF + NP]: ./additional-feature-np.md#lodash-core-proposal--additional-features-bppppfmt 400 | [Lodash + CP]: ./core-real-examples.md#lodash 401 | [Lodash]: https://lodash.com/ 402 | [mAAdhaTTah]: https://github.com/mAAdhaTTah/ 403 | [make my code easier to read]: ./goals.md#make-my-code-easier-to-read 404 | [MDN operator precedence]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence 405 | [MDN operator precedence]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table 406 | [method-extraction inline caching]: https://github.com/tc39/proposal-bind-operator/issues/46 407 | [mindeavor]: https://github.com/gilbert 408 | [mode errors]: https://en.wikipedia.org/wiki/Mode_(computer_interface)#Mode_errors 409 | [motivation]: ./readme.md 410 | [Node-stream piping]: https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options 411 | [Node.js `util.promisify`]: https://nodejs.org/api/util.html#util_util_promisify_original 412 | [nomenclature]: ./nomenclature.md 413 | [novice learnability]: ./goals.md#novice-learnability 414 | [nullish coalescing proposal]: https://github.com/tc39/proposal-nullish-coalescing/ 415 | [object initializers’ Computed Property Contains rule]: https://tc39.github.io/ecma262/#sec-object-initializer-static-semantics-computedpropertycontains 416 | [OCaml pipe]: http://blog.shaynefletcher.org/2013/12/pipelining-with-operator-in-ocaml.html 417 | [operator precedence]: ./core-syntax.md#operator-precedence-and-associativity 418 | [opt-in behavior]: ./goals.md#opt-in-behavior 419 | [optional `catch` binding]: ./relations.md#optional-catch-binding 420 | [optional-chaining syntax proposal]: https://github.com/tc39/proposal-optional-chaining 421 | [other browsers’ console variables]: https://www.andismith.com/blogs/2011/11/25-dev-tool-secrets/ 422 | [other ECMAScript proposals]: ./relations.md#other-ecmascript-proposals 423 | [other goals]: ./goals.md#other-goals 424 | [pattern matching]: ./relations.md#pattern-matching 425 | [partial function application]: ./goals.md#partial-function-application 426 | [PEP 20]: https://www.python.org/dev/peps/pep-0020/ 427 | [Perl 6 pipe]: https://docs.perl6.org/language/operators#infix_==> 428 | [Perl 6 topicization]: https://www.perl.com/pub/2002/10/30/topic.html/ 429 | [Perl 6’s given block]: https://docs.perl6.org/language/control#given 430 | [pipeline functions]: ./additional-feature-pf.md 431 | [Pipeline Proposal 1]: https://github.com/tc39/proposal-pipeline-operator/wiki#proposal-1-f-sharp-only 432 | [Pipeline Proposal 4]: https://github.com/tc39/proposal-pipeline-operator/wiki#proposal-4-smart-mix 433 | [pipeline syntax]: ./core-syntax.md 434 | [pipelines]: ./readme.md 435 | [previous pipeline-placeholder discussions]: https://github.com/tc39/proposal-pipeline-operator/issues?q=placeholder 436 | [primary topic]: ./readme.md 437 | [private class fields]: https://github.com/tc39/proposal-class-fields/ 438 | [pure functions]: https://en.wikipedia.org/wiki/Pure_function 439 | [R pipe]: https://cran.r-project.org/web/packages/magrittr/vignettes/magrittr.html 440 | [Ramda + CP + BP + PF + NP]: ./additional-feature-np.md#ramda-core-proposal--additional-features-bppfmt 441 | [Ramda + CP + BP + PF]: ./additional-feature-pf.md#ramda-core-proposal--additional-feature-bppf 442 | [Ramda wiki cookbook]: https://github.com/ramda/ramda/wiki/Cookbook 443 | [Ramda]: http://ramdajs.com/ 444 | [relations to other work]: ./relations.md 445 | [REPLs]: https://en.wikipedia.org/wiki/Read–eval–print_loop 446 | [rest topic]: ./additional-feature-np.md 447 | [reverse Polish notation]: https://en.wikipedia.org/wiki/Reverse_Polish_notation 448 | [robust method extraction]: https://github.com/tc39/proposal-pipeline-operator/issues/110#issuecomment-374367888 449 | [Ron Buckton]: https://github.com/rbuckton 450 | [secondary topic]: ./additional-feature-np.md 451 | [semantic clarity]: ./goals.md#semantic-clarity 452 | [simonstaton functional composition]: https://github.com/simonstaton/Function.prototype.compose-TC39-Proposal 453 | [simple scoping]: ./goals.md#simple-scoping 454 | [sindresorhus]: https://github.com/sindresorhus 455 | [smart step syntax]: ./core-syntax.md 456 | [smart pipelines]: ./readme.md#smart-pipelines 457 | [Standard Style]: https://standardjs.com/ 458 | [static analyzability]: ./goals.md#static-analyzability 459 | [statically analyzable]: ./goals.md#static-analyzability 460 | [statically detectable early errors]: ./goals.md#static-analyzability 461 | [syntactic locality]: ./goals.md#syntactic-locality 462 | [tacit programming]: https://en.wikipedia.org/wiki/Tacit_programming 463 | [TC39 60th meeting, pipelines]: https://tc39.github.io/tc39-notes/2017-09_sep-26.html#11iia-pipeline-operator 464 | [TC39 process]: https://tc39.github.io/process-document/ 465 | [tc39/proposal-decorators#30]: tc39/proposal-decorators#30 466 | [tc39/proposal-decorators#42]: tc39/proposal-decorators#42 467 | [tc39/proposal-decorators#60]: tc39/proposal-decorators#60 468 | [Tennent correspondence principle]: http://gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html 469 | [term rewriting]: ./term-rewriting.md 470 | [terse composition]: ./goals.md#terse-composition 471 | [terse function application]: ./goals.md#terse-function-application 472 | [terse function calls]: ./goals.md#terse-function-calls 473 | [terse method extraction]: ./goals.md#terse-method-extraction 474 | [terse parentheses]: ./goals.md#terse-parentheses 475 | [terse partial application]: ./goals.md#terse-partial-application 476 | [terse variables]: ./goals.md#terse-variables 477 | [tertiary topic]: ./additional-feature-np.md 478 | [TheNavigateur functional composition]: https://github.com/TheNavigateur/proposal-pipeline-operator-for-function-composition 479 | [topic and comment]: https://en.wikipedia.org/wiki/Topic_and_comment 480 | [topic references in other programming languages]: ./relations.md#topic-references-in-other-programming-languages 481 | [topic style]: ./core-syntax.md#topic-style 482 | [topic variables in other languages]: https://rosettacode.org/wiki/Topic_variable 483 | [topic-token bikeshedding]: https://github.com/tc39/proposal-pipeline-operator/issues/91 484 | [Underscore.js + CP + BP + PP]: ./additional-feature-pp.md#underscorejs-core-proposal--additional-feature-bppp 485 | [Underscore.js + CP]: ./core-real-examples.md#underscorejs 486 | [Underscore.js]: http://underscorejs.org 487 | [Unix pipe]: https://en.wikipedia.org/wiki/Pipeline_(Unix 488 | [untangled flow]: ./goals.md#untangled-flow 489 | [Visual Basic’s `select` statement]: https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/select-case-statement 490 | [WebKit console variables]: https://webkit.org/blog/829/web-inspector-updates/ 491 | [WHATWG Fetch + CP]: ./core-real-examples.md#whatwg-fetch-standard 492 | [WHATWG Fetch Standard]: https://fetch.spec.whatwg.org/ 493 | [WHATWG Streams + CP + BP + PF + NP]: ./additional-feature-np.md#whatwg-streams-standard-core-proposal--additional-features-bppfmt 494 | [WHATWG Streams + CP + BP + PF]: ./additional-feature-pf.md#whatwg-streams-standard-core-proposal--additional-feature-bppf 495 | [WHATWG Streams Standard]: https://stream.spec.whatwg.org/ 496 | [WHATWG-stream piping]: https://streams.spec.whatwg.org/#pipe-chains 497 | [Wikipedia: term rewriting]: https://en.wikipedia.org/wiki/Term_rewriting 498 | [zero runtime cost]: ./goals.md#zero-runtime-cost 499 | -------------------------------------------------------------------------------- /core-real-examples.md: -------------------------------------------------------------------------------- 1 | # Core Proposal real-world examples 2 | Living Document. J. S. Choi, 2018-12. 3 | 4 | ### WHATWG Fetch Standard 5 | The [WHATWG Fetch Standard][] contains several examples of using the DOM `fetch` 6 | function, resolving its promises into values, then processing the values in 7 | various ways. These examples may become more easily readable with smart pipelines. 8 | 9 | 10 | 11 | 12 | 16 | 17 | 35 | 49 | 70 | 92 | 109 |
With smart pipelines 13 | Status quo 14 | 15 |
18 | 19 | ```js 20 | '/music/pk/altes-kamuffel' 21 | |> await fetch(#) 22 | |> await #.blob() 23 | |> playBlob; 24 | ``` 25 | 26 | 27 | 28 | ```js 29 | fetch('/music/pk/altes-kamuffel') 30 | .then(res => res.blob()) 31 | .then(playBlob); 32 | ``` 33 | 34 |
36 | [Equivalent to above.] 37 | 38 | 39 | 40 | ```js 41 | playBlob( 42 | await ( 43 | await fetch('/music/pk/altes-kamuffel') 44 | ).blob() 45 | ); 46 | ``` 47 | 48 |
50 | 51 | ```js 52 | 'https://example.com/' 53 | |> await fetch(#, { method: 'HEAD' }) 54 | |> #.headers.get('content-type') 55 | |> console.log; 56 | ``` 57 | 58 | 59 | 60 | ```js 61 | fetch('https://example.com/', 62 | { method: 'HEAD' } 63 | ).then(response => 64 | console.log( 65 | response.headers.get('content-type')) 66 | ); 67 | ``` 68 | 69 |
71 | 72 | ```js 73 | 'https://example.com/' 74 | |> await fetch(#, { method: 'HEAD' }) 75 | |> #.headers.get('content-type') 76 | |> console.log; 77 | ``` 78 | 79 | 80 | 81 | ```js 82 | console.log( 83 | (await 84 | fetch('https://example.com/', 85 | { method: 'HEAD' } 86 | ) 87 | ).headers.get('content-type') 88 | ); 89 | ``` 90 | 91 |
93 | [Equivalent to above.] 94 | 95 | 96 | 97 | ```js 98 | { 99 | const url = 'https://example.com/'; 100 | const response = 101 | await fetch(url, { method: 'HEAD' }); 102 | const contentType = 103 | response.headers.get('content-type'); 104 | console.log(contentType); 105 | } 106 | ``` 107 | 108 |
110 | 111 | ```js 112 | 'https://pk.example/berlin-calling' 113 | |> await fetch(#, { mode: 'cors' }) 114 | |> do { 115 | if (#.headers.get('content-type') 116 | && #.headers.get('content-type') 117 | .toLowerCase() 118 | .indexOf('application/json') >= 0 119 | ) 120 | return #.json(); 121 | else 122 | throw new TypeError(); 123 | } 124 | |> await #.json() 125 | |> processJSON; 126 | ``` 127 | This example uses [`do` expressions][], which come from another ES proposal, 128 | and which work well with smart pipelines--in this case to embed `if`–`else` statements. 129 | 130 | 131 | 132 | ```js 133 | fetch('https://pk.example/berlin-calling', 134 | { mode: 'cors' } 135 | ).then(response => { 136 | if (response.headers.get('content-type') 137 | && response.headers.get('content-type') 138 | .toLowerCase() 139 | .indexOf('application/json') >= 0 140 | ) 141 | return response.json(); 142 | else 143 | throw new TypeError(); 144 | }).then(processJSON); 145 | ``` 146 | 147 |
148 | 149 | ### jQuery 150 | As the single most-used JavaScript library in the world, [jQuery][] has provided 151 | an alternative human-ergonomic API to the DOM since 2006. jQuery is under the 152 | stewardship of the [JS Foundation][], a member organization of TC39 through which 153 | jQuery’s developers are represented in TC39. jQuery’s API requires complex data 154 | processing that becomes more readable with smart pipelines. 155 | 156 | 157 | 158 | 159 | 163 | 164 | 194 | 214 | 232 | 260 | 286 | 301 |
With smart pipelines 160 | Status quo 161 | 162 |
165 | 166 | ```js 167 | return data 168 | |> buildFragment([#], context, scripts) 169 | |> #.childNodes 170 | |> jQuery.merge([], #); 171 | ``` 172 | The path that a reader’s eyes must trace while reading this pipeline moves 173 | straight down, with some movement toward the right then back: from `data` to 174 | `buildFragment` (and its arguments), then `.childNodes`, then `jQuery.merge`. 175 | Here, no one-off-variable assignment is necessary. 176 | 177 | 178 | 179 | ```js 180 | parsed = buildFragment( 181 | [ data ], context, scripts 182 | ); 183 | return jQuery.merge( 184 | [], parsed.childNodes 185 | ); 186 | ``` 187 | From [jquery/src/core/parseHTML.js][]. In this code, the eyes first must look 188 | for `data` – then upwards to `parsed = buildFragment` (and then back for 189 | `buildFragment`’s other arguments) – then down, searching for the location of 190 | the `parsed` variable in the next statement – then right when noticing its 191 | `.childNodes` postfix – then back upward to `return jQuery.merge`. 192 | 193 |
195 | 196 | ```js 197 | (key |> toType) === 'object'; 198 | ``` 199 | ```js 200 | key |> toType |> # === 'object'; 201 | ``` 202 | `|>` has a looser precedence than most operators, including `===`. (Only 203 | assignment operators, arrow function `=>`, yield operators, and the comma 204 | operator are any looser.) 205 | 206 | 207 | 208 | ```js 209 | toType(key) === 'object'; 210 | ``` 211 | From [jquery/src/core/access.js][]. 212 | 213 |
215 | 216 | ```js 217 | context = context 218 | |> # instanceof jQuery 219 | ? #[0] : #; 220 | ``` 221 | 222 | 223 | 224 | ```js 225 | context = 226 | context instanceof jQuery 227 | ? context[0] : context; 228 | ``` 229 | From [jquery/src/core/access.js][]. 230 | 231 |
233 | 234 | ```js 235 | context 236 | |> # && #.nodeType 237 | ? #.ownerDocument || # 238 | : document 239 | |> jQuery.parseHTML(match[1], #, true) 240 | |> jQuery.merge; 241 | ``` 242 | 243 | 244 | 245 | ```js 246 | jQuery.merge( 247 | this, jQuery.parseHTML( 248 | match[1], 249 | context && context.nodeType 250 | ? context.ownerDocument 251 | || context 252 | : document, 253 | true 254 | ) 255 | ); 256 | ``` 257 | From [jquery/src/core/init.js][]. 258 | 259 |
261 | 262 | ```js 263 | match 264 | |> context[#] 265 | |> (this[match] |> isFunction) 266 | ? this[match](#); 267 | : this.attr(match, #); 268 | ``` 269 | Note how, in this version, the parallelism between the two clauses is very 270 | clear: they both share the form `match |> context[#] |> something(match, #)`. 271 | 272 | 273 | 274 | ```js 275 | if (isFunction(this[match])) { 276 | this[match](context[match]); 277 | } else 278 | this.attr(match, context[match]); 279 | } 280 | ``` 281 | From [jquery/src/core/init.js][]. Here, the parallelism between the clauses 282 | is somewhat less clear: the common expression `context[match]` is at the end 283 | of both clauses, at a different offset from the margin. 284 | 285 |
287 | 288 | ```js 289 | elem = match[2] 290 | |> document.getElementById; 291 | ``` 292 | 293 | 294 | 295 | ```js 296 | elem = document.getElementById(match[2]); 297 | ``` 298 | From [jquery/src/core/init.js][]. 299 | 300 |
302 | 303 | ```js 304 | // Handle HTML strings 305 | if (…) 306 | … 307 | // Handle $(expr, $(...)) 308 | else if (!# || #.jquery) 309 | return context 310 | |> # || root 311 | |> #.find(selector); 312 | // Handle $(expr, context) 313 | else 314 | return context 315 | |> this.constructor 316 | |> #.find(selector); 317 | ``` 318 | The parallelism between the final two clauses becomes clearer here too. 319 | They both are of the form `return context |> something |> #.find(selector)`. 320 | 321 | 322 | 323 | ```js 324 | // Handle HTML strings 325 | if (…) 326 | … 327 | // Handle $(expr, $(...)) 328 | else if (!context || context.jquery) 329 | return (context || root).find(selector); 330 | // Handle $(expr, context) 331 | else 332 | return this.constructor(context) 333 | .find(selector); 334 | ``` 335 | From [jquery/src/core/init.js][]. The parallelism is much less clear here. 336 | 337 |
338 | 339 | ### Underscore.js 340 | [Underscore.js][] is another utility library very widely used since 2009, 341 | providing numerous functions that manipulate arrays, objects, and other 342 | functions. It too has a codebase that transforms values through many expressions 343 | – a codebase whose readability would therefore benefit from smart pipelines. 344 | 345 | 346 | 347 | 348 | 352 | 353 | 382 | 405 | 438 |
With smart pipelines 349 | Status quo 350 | 351 |
354 | 355 | ```js 356 | function (obj, pred, context) { 357 | return obj 358 | |> isArrayLike 359 | |> # ? _.findIndex : _.findKey 360 | |> #(obj, pred, context) 361 | |> (# !== void 0 && # !== -1) 362 | ? obj[#] : undefined; 363 | } 364 | ``` 365 | 366 | 367 | 368 | ```js 369 | function (obj, pred, context) { 370 | var key; 371 | if (isArrayLike(obj)) { 372 | key = _.findIndex(obj, pred, context); 373 | } else { 374 | key = _.findKey(obj, pred, context); 375 | } 376 | if (key !== void 0 && key !== -1) 377 | return obj[key]; 378 | } 379 | ``` 380 | 381 |
383 | 384 | ```js 385 | function (obj, pred, context) { 386 | return pred 387 | |> cb 388 | |> _.negate 389 | |> _.filter(obj, #, context); 390 | } 391 | ``` 392 | 393 | 394 | 395 | ```js 396 | function (obj, pred, context) { 397 | return _.filter(obj, 398 | _.negate(cb(pred)), 399 | context 400 | ); 401 | } 402 | ``` 403 | 404 |
406 | 407 | ```js 408 | function ( 409 | srcFn, boundFn, ctxt, callingCtxt, args 410 | ) { 411 | if (!(callingCtxt instanceof boundFn)) 412 | return srcFn.apply(ctxt, args); 413 | var self = srcFn 414 | |> #.prototype |> baseCreate; 415 | return self 416 | |> srcFn.apply(#, args) 417 | |> _.isObject(#) ? # : self; 418 | } 419 | ``` 420 | 421 | 422 | 423 | ```js 424 | function ( 425 | srcFn, boundFn, 426 | ctxt, callingCtxt, args 427 | ) { 428 | if (!(callingCtxt instanceof boundFn)) 429 | return srcFn.apply(ctxt, args); 430 | var self = baseCreate(srcFn.prototype); 431 | var result = srcFn.apply(self, args); 432 | if (_.isObject(result)) return result; 433 | return self; 434 | } 435 | ``` 436 | 437 |
439 | 440 | ```js 441 | function (obj) { 442 | return obj 443 | |> # == null 444 | ? 0 445 | : #|> isArrayLike 446 | ? #|> #.length 447 | : #|> _.keys |> #.length; 448 | }; 449 | } 450 | ``` 451 | Smart pipelines make parallelism between all three clauses becomes clearer:\ 452 | `0` if it is nullish,\ 453 | `#|> #.length` if it is array-like, and\ 454 | `#|> something |> #.length` otherwise.\ 455 | (Technically, `#|> #.length` could simply be `#.length`, but it is written in 456 | this redundant form in order to emphasis its parallelism with the other branch.) 457 | 458 | [This particular example becomes even clearer][Underscore.js + CP + BP + PP] 459 | when paired with [Additional Feature BP][]. 460 | 461 | 462 | 463 | ```js 464 | function (obj) { 465 | if (obj == null) return 0; 466 | return isArrayLike(obj) 467 | ? obj.length 468 | : _.keys(obj).length; 469 | } 470 | ``` 471 | 472 |
473 | 474 | ### Lodash 475 | [Lodash][] is a fork of [Underscore.js][] that remains under rapid active 476 | development. Along with Underscore.js’ other utility functions, Lodash provides 477 | many other high-order functions that attempt to make [functional programming][] 478 | more ergonomic. Like [jQuery][], Lodash is under the stewardship of the 479 | [JS Foundation][], a member organization of TC39, through which Lodash’s developers 480 | also have TC39 representation. And like jQuery and Underscore.js, Lodash’s API 481 | involves complex data processing that becomes more readable with smart pipelines. 482 | 483 | 484 | 485 | 486 | 490 | 491 | 521 | 541 | 566 |
With smart pipelines 487 | Status quo 488 | 489 |
492 | 493 | ```js 494 | function hashGet (key) { 495 | return this.__data__ 496 | |> nativeCreate 497 | ? (#[key] === HASH_UNDEFINED 498 | ? undefined : #) 499 | : hashOwnProperty.call(#, key) 500 | ? #[key] 501 | : undefined; 502 | } 503 | ``` 504 | 505 | 506 | 507 | ```js 508 | function hashGet (key) { 509 | var data = this.__data__; 510 | if (nativeCreate) { 511 | var result = data[key]; 512 | return result === HASH_UNDEFINED 513 | ? undefined : result; 514 | } 515 | return hasOwnProperty.call(data, key) 516 | ? data[key] : undefined; 517 | } 518 | ``` 519 | 520 |
522 | 523 | ```js 524 | function listCacheHas (key) { 525 | return this.__data__ 526 | |> assocIndexOf(#, key) 527 | |> # > -1; 528 | } 529 | ``` 530 | 531 | 532 | 533 | ```js 534 | function listCacheHas (key) { 535 | return assocIndexOf(this.__data__, key) 536 | > -1; 537 | } 538 | ``` 539 | 540 |
542 | 543 | ```js 544 | function mapCacheDelete (key) { 545 | const result = key 546 | |> getMapData(this, #) 547 | |> #['delete'] 548 | |> #(key); 549 | this.size -= result ? 1 : 0; 550 | return result; 551 | } 552 | ``` 553 | 554 | 555 | 556 | ```js 557 | function mapCacheDelete (key) { 558 | var result = 559 | getMapData(this, key)['delete'](key); 560 | this.size -= result ? 1 : 0; 561 | return result; 562 | } 563 | ``` 564 | 565 |
567 | 568 | ```js 569 | function castPath (value, object) { 570 | return value |> 571 | #|> isArray 572 | ? # 573 | : (#|> isKey(#, object)) 574 | ? [#] 575 | : #|> toString |> stringToPath; 576 | } 577 | ``` 578 | 579 | 580 | 581 | ```js 582 | function castPath (value, object) { 583 | if (isArray(value)) { 584 | return value; 585 | } 586 | return isKey(value, object) 587 | ? [value] 588 | : stringToPath(toString(value)); 589 | } 590 | ``` 591 | 592 |
593 | 594 | ["data-to-ink" visual ratio]: https://www.darkhorseanalytics.com/blog/data-looks-better-naked 595 | ["don’t break my code"]: ./goals.md#dont-break-my-code 596 | ["don’t make me overthink"]: ./goals.md#dont-make-me-overthink 597 | ["don’t shoot me in the foot"]: ./goals.md#dont-shoot-me-in-the-foot 598 | ["make my code easier to read"]: ./goals.md#make-my-code-easier-to-read 599 | [`??:`]: https://github.com/tc39/proposal-nullish-coalescing/pull/23 600 | [`do` expression]: ./relations.md#do-expressions 601 | [`do` expressions]: ./relations.md#do-expressions 602 | [`for` iteration statements]: https://tc39.github.io/ecma262/#sec-iteration-statements 603 | [`in` relational operator]: https://tc39.github.io/ecma262/#sec-relational-operators 604 | [`match` expressions]: ./relations.md#pattern-matching 605 | [`new.target`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new.target 606 | [Additional Feature BA]: ./additional-feature-ba.md 607 | [Additional Feature BC]: ./additional-feature-bc.md 608 | [Additional Feature BP]: ./additional-feature-bp.md 609 | [Additional Feature NP]: ./additional-feature-np.md 610 | [Additional Feature PF]: ./additional-feature-pf.md 611 | [Additional Feature TS]: ./additional-feature-ts.md 612 | [additional features]: ./readme.md#additional-features 613 | [annevk]: https://github.com/annevk 614 | [antecedent]: https://en.wikipedia.org/wiki/Antecedent_(grammar) 615 | [arbitrary associativity]: ./goals.md#arbitrary-associativity 616 | [ASI]: https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion 617 | [associative property]: https://en.wikipedia.org/wiki/Associative_property 618 | [async pipeline functions]: ./additional-feature-pf.md 619 | [Babel plugin]: https://github.com/valtech-nyc/babel/ 620 | [Babel update summary]: https://github.com/babel/proposals/issues/29#issuecomment-372828328 621 | [background]: ./readme.md 622 | [backward compatibility]: ./goals.md#backward-compatibility 623 | [bare awaited function call]: ./core-syntax.md#bare-style 624 | [bare constructor call]: ./core-syntax.md#bare-style 625 | [bare function call]: ./core-syntax.md#bare-style 626 | [bare style]: ./core-syntax.md#bare-style 627 | [binding]: https://en.wikipedia.org/wiki/Binding_(linguistics) 628 | [block parameters]: ./relations.md#block-parameters 629 | [Clojure compact function]: https://clojure.org/reference/reader#_dispatch 630 | [Clojure pipe]: https://clojuredocs.org/clojure.core/as-%3E 631 | [completion records]: https://timothygu.me/es-howto/#completion-records-and-shorthands 632 | [concatenative programming]: https://en.wikipedia.org/wiki/Concatenative_programming_language 633 | [conceptual generality]: ./goals.md#conceptual-generality 634 | [Core Proposal]: ./readme.md 635 | [core-real-examples.md]: ./core-real-examples.md 636 | [currying]: https://en.wikipedia.org/wiki/Currying 637 | [cyclomatic complexity]: https://en.wikipedia.org/wiki/Cyclomatic_complexity#Applications 638 | [cyclomatic simplicity]: ./goals.md#cyclomatic-simplicity 639 | [dataflow programming]: https://en.wikipedia.org/wiki/Dataflow_programming 640 | [distinguishable punctuators]: ./goals.md#distinguishable-punctuators 641 | [don’t break my code]: ./goals.md#dont-break-my-code 642 | [DSLs]: https://en.wikipedia.org/wiki/Domain-specific_language 643 | [early error rule]: ./goals.md#static-analyzability 644 | [early error rules]: ./goals.md#static-analyzability 645 | [early error]: ./goals.md#static-analyzability 646 | [early errors]: ./goals.md#static-analyzability 647 | [ECMAScript _Identifier Name_]: https://tc39.github.io/ecma262/#prod-IdentifierName 648 | [ECMAScript _Identifier Reference_]: https://tc39.github.io/ecma262/#prod-IdentifierReference 649 | [ECMAScript _Member Expression_]: https://tc39.github.io/ecma262/#prod-MemberExpression 650 | [ECMAScript § The Syntactic Grammar]: https://tc39.github.io/ecma262/#sec-syntactic-grammar 651 | [ECMAScript `new` operator, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-new-operator-runtime-semantics-evaluation 652 | [ECMAScript arrow functions, § SS: Contains]: https://tc39.github.io/ecma262/#sec-arrow-function-definitions-static-semantics-contains 653 | [ECMAScript Assignment-level Expressions]: https://tc39.github.io/ecma262/#sec-assignment-operators 654 | [ECMAScript block parameters]: https://github.com/samuelgoto/proposal-block-params 655 | [ECMAScript Blocks, § RS: Block Declaration Instantiation]: https://tc39.github.io/ecma262/#sec-blockdeclarationinstantiation 656 | [ECMAScript Blocks, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-block-runtime-semantics-evaluation 657 | [ECMAScript Declarative Environment Records]: https://tc39.github.io/ecma262/#sec-declarative-environment-records 658 | [ECMAScript function binding]: https://github.com/zenparsing/es-function-bind 659 | [ECMAScript Function Calls, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-function-calls-runtime-semantics-evaluation 660 | [ECMAScript Function Environment Records]: https://tc39.github.io/ecma262/#sec-function-environment-records 661 | [ECMAScript Functions and Classes § Generator Function Definitions]: https://tc39.github.io/ecma262/#sec-generator-function-definitions 662 | [ECMAScript Get This Environment]: https://tc39.github.io/ecma262/#sec-getthisenvironment 663 | [ECMAScript headless-arrow proposal]: https://bterlson.github.io/headless-arrows/ 664 | [ECMAScript Lexical Environments]: https://tc39.github.io/ecma262/#sec-lexical-environments 665 | [ECMAScript Lexical Grammar]: https://tc39.github.io/ecma262/#sec-ecmascript-language-lexical-grammar 666 | [ECMAScript LHS expressions]: https://tc39.github.io/ecma262/#sec-left-hand-side-expressions 667 | [ECMAScript Lists and Records]: https://tc39.github.io/ecma262/#sec-list-and-record-specification-type 668 | [ECMAScript Notational Conventions, § Algorithm Conventions]: https://tc39.github.io/ecma262/#sec-algorithm-conventions-abstract-operations 669 | [ECMAScript Notational Conventions, § Grammars]: https://tc39.github.io/ecma262/#sec-syntactic-and-lexical-grammars 670 | [ECMAScript Notational Conventions, § Lexical Grammar]: https://tc39.github.io/ecma262/#sec-lexical-and-regexp-grammars 671 | [ECMAScript Notational Conventions, § Runtime Semantics]: https://tc39.github.io/ecma262/#sec-runtime-semantics 672 | [ECMAScript optional `catch` binding]: https://github.com/tc39/proposal-optional-catch-binding 673 | [ECMAScript partial application]: https://github.com/tc39/proposal-partial-application 674 | [ECMAScript pattern matching]: https://github.com/tc39/proposal-pattern-matching 675 | [ECMAScript Primary Expressions]: https://tc39.github.io/ecma262/#prod-PrimaryExpression 676 | [ECMAScript Property Accessors, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-property-accessors-runtime-semantics-evaluation 677 | [ECMAScript Punctuators]: https://tc39.github.io/ecma262/#sec-punctuators 678 | [ECMAScript static semantic rules]: https://tc39.github.io/ecma262/#sec-static-semantic-rules 679 | [Elixir pipe]: https://hexdocs.pm/elixir/Kernel.html#%7C%3E/2 680 | [Elm pipe]: http://elm-lang.org/docs/syntax#infix-operators 681 | [essential complexity]: https://en.wikipedia.org/wiki/Essential_complexity 682 | [expressions and operators (MDN)]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators 683 | [expressive versatility]: ./goals.md#expressive-versatility 684 | [F# pipe]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/functions/index#function-composition-and-pipelining 685 | [first pipe-operator proposal]: https://github.com/tc39/proposal-pipeline-operator/blob/37119110d40226476f7af302a778bc981f606cee/README.md 686 | [footguns]: https://en.wiktionary.org/wiki/footgun 687 | [formal BA]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-ba 688 | [formal BC]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-bc 689 | [formal BP]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-bp 690 | [formal CP]: https://jschoi.org/18/es-smart-pipelines/spec#introduction 691 | [formal NP]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-np 692 | [formal PF]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-pf 693 | [formal pipeline specification]: https://jschoi.org/18/es-smart-pipelines/spec 694 | [formal TS]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-ts 695 | [forward compatibility]: ./goals.md#forward-compatibility 696 | [forward compatible]: ./goals.md#forward-compatibility 697 | [function bind operator `::`]: ./relations.md#function-bind-operator 698 | [function binding]: ./relations.md#function-binding 699 | [function composition]: ./relations.md#function-composition 700 | [functional programming]: https://en.wikipedia.org/wiki/Functional_programming 701 | [gajus functional composition]: https://github.com/gajus/babel-plugin-transform-function-composition 702 | [garden-path syntax]: https://en.wikipedia.org/wiki/Garden_path_sentence 703 | [GitHub issue tracker]: https://github.com/tc39/proposal-pipeline-operator/issues 704 | [goals]: ./goals.md 705 | [Hack pipe]: https://docs.hhvm.com/hack/operators/pipe-operator 706 | [Huffman coding]: https://en.wikipedia.org/wiki/Huffman_coding 707 | [human writability]: ./goals.md#human-writability 708 | [i-am-tom functional composition]: https://github.com/fantasyland/ECMAScript-proposals/issues/1#issuecomment-306243513 709 | [identity function]: https://en.wikipedia.org/wiki/Identity_function 710 | [IIFEs]: https://en.wikipedia.org/wiki/Immediately-invoked_function_expression 711 | [immutable objects]: https://en.wikipedia.org/wiki/Immutable_object 712 | [incidental complexity]: https://en.wikipedia.org/wiki/Incidental_complexity 713 | [intro]: readme.md 714 | [isiahmeadows functional composition]: https://github.com/isiahmeadows/function-composition-proposal 715 | [jashkenas]: https://github.com/jashkenas 716 | [jQuery + CP]: ./core-real-examples.md#jquery 717 | [jQuery]: https://jquery.com/ 718 | [jquery/src/core/access.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/access.js 719 | [jquery/src/core/init.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/init.js 720 | [jquery/src/core/parseHTML.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/parseHTML.js 721 | [JS Foundation]: https://js.foundation/ 722 | [Julia pipe]: https://docs.julialang.org/en/stable/stdlib/base/#Base.:|> 723 | [lexical topic]: https://jschoi.org/18/es-smart-pipelines/spec#sec-lexical-topics 724 | [lexically hygienic]: https://en.wikipedia.org/wiki/Hygienic_macro 725 | [littledan invitation]: https://github.com/tc39/proposal-pipeline-operator/issues/89#issuecomment-363853394 726 | [littledan]: https://github.com/littledan 727 | [LiveScript pipe]: http://livescript.net/#operators-piping 728 | [Lodash + CP + BP + PF]: ./additional-feature-pf.md#lodash-core-proposal--additional-feature-bppf 729 | [Lodash + CP + BP + PP + PF + NP]: ./additional-feature-np.md#lodash-core-proposal--additional-features-bppppfmt 730 | [Lodash + CP]: ./core-real-examples.md#lodash 731 | [Lodash]: https://lodash.com/ 732 | [mAAdhaTTah]: https://github.com/mAAdhaTTah/ 733 | [make my code easier to read]: ./goals.md#make-my-code-easier-to-read 734 | [MDN operator precedence]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence 735 | [MDN operator precedence]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table 736 | [method-extraction inline caching]: https://github.com/tc39/proposal-bind-operator/issues/46 737 | [mindeavor]: https://github.com/gilbert 738 | [mode errors]: https://en.wikipedia.org/wiki/Mode_(computer_interface)#Mode_errors 739 | [motivation]: ./readme.md 740 | [Node-stream piping]: https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options 741 | [Node.js `util.promisify`]: https://nodejs.org/api/util.html#util_util_promisify_original 742 | [nomenclature]: ./nomenclature.md 743 | [novice learnability]: ./goals.md#novice-learnability 744 | [nullish coalescing proposal]: https://github.com/tc39/proposal-nullish-coalescing/ 745 | [object initializers’ Computed Property Contains rule]: https://tc39.github.io/ecma262/#sec-object-initializer-static-semantics-computedpropertycontains 746 | [OCaml pipe]: http://blog.shaynefletcher.org/2013/12/pipelining-with-operator-in-ocaml.html 747 | [operator precedence]: ./core-syntax.md#operator-precedence-and-associativity 748 | [opt-in behavior]: ./goals.md#opt-in-behavior 749 | [optional `catch` binding]: ./relations.md#optional-catch-binding 750 | [optional-chaining syntax proposal]: https://github.com/tc39/proposal-optional-chaining 751 | [other browsers’ console variables]: https://www.andismith.com/blogs/2011/11/25-dev-tool-secrets/ 752 | [other ECMAScript proposals]: ./relations.md#other-ecmascript-proposals 753 | [other goals]: ./goals.md#other-goals 754 | [pattern matching]: ./relations.md#pattern-matching 755 | [partial function application]: ./goals.md#partial-function-application 756 | [PEP 20]: https://www.python.org/dev/peps/pep-0020/ 757 | [Perl 6 pipe]: https://docs.perl6.org/language/operators#infix_==> 758 | [Perl 6 topicization]: https://www.perl.com/pub/2002/10/30/topic.html/ 759 | [Perl 6’s given block]: https://docs.perl6.org/language/control#given 760 | [pipeline functions]: ./additional-feature-pf.md 761 | [Pipeline Proposal 1]: https://github.com/tc39/proposal-pipeline-operator/wiki#proposal-1-f-sharp-only 762 | [Pipeline Proposal 4]: https://github.com/tc39/proposal-pipeline-operator/wiki#proposal-4-smart-mix 763 | [pipeline syntax]: ./core-syntax.md 764 | [pipelines]: ./readme.md 765 | [previous pipeline-placeholder discussions]: https://github.com/tc39/proposal-pipeline-operator/issues?q=placeholder 766 | [primary topic]: ./readme.md 767 | [private class fields]: https://github.com/tc39/proposal-class-fields/ 768 | [pure functions]: https://en.wikipedia.org/wiki/Pure_function 769 | [R pipe]: https://cran.r-project.org/web/packages/magrittr/vignettes/magrittr.html 770 | [Ramda + CP + BP + PF + NP]: ./additional-feature-np.md#ramda-core-proposal--additional-features-bppfmt 771 | [Ramda + CP + BP + PF]: ./additional-feature-pf.md#ramda-core-proposal--additional-feature-bppf 772 | [Ramda wiki cookbook]: https://github.com/ramda/ramda/wiki/Cookbook 773 | [Ramda]: http://ramdajs.com/ 774 | [relations to other work]: ./relations.md 775 | [REPLs]: https://en.wikipedia.org/wiki/Read–eval–print_loop 776 | [rest topic]: ./additional-feature-np.md 777 | [reverse Polish notation]: https://en.wikipedia.org/wiki/Reverse_Polish_notation 778 | [robust method extraction]: https://github.com/tc39/proposal-pipeline-operator/issues/110#issuecomment-374367888 779 | [Ron Buckton]: https://github.com/rbuckton 780 | [secondary topic]: ./additional-feature-np.md 781 | [semantic clarity]: ./goals.md#semantic-clarity 782 | [simonstaton functional composition]: https://github.com/simonstaton/Function.prototype.compose-TC39-Proposal 783 | [simple scoping]: ./goals.md#simple-scoping 784 | [sindresorhus]: https://github.com/sindresorhus 785 | [smart step syntax]: ./core-syntax.md 786 | [smart pipelines]: ./readme.md#smart-pipelines 787 | [Standard Style]: https://standardjs.com/ 788 | [static analyzability]: ./goals.md#static-analyzability 789 | [statically analyzable]: ./goals.md#static-analyzability 790 | [statically detectable early errors]: ./goals.md#static-analyzability 791 | [syntactic locality]: ./goals.md#syntactic-locality 792 | [tacit programming]: https://en.wikipedia.org/wiki/Tacit_programming 793 | [TC39 60th meeting, pipelines]: https://tc39.github.io/tc39-notes/2017-09_sep-26.html#11iia-pipeline-operator 794 | [TC39 process]: https://tc39.github.io/process-document/ 795 | [tc39/proposal-decorators#30]: tc39/proposal-decorators#30 796 | [tc39/proposal-decorators#42]: tc39/proposal-decorators#42 797 | [tc39/proposal-decorators#60]: tc39/proposal-decorators#60 798 | [Tennent correspondence principle]: http://gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html 799 | [term rewriting]: ./term-rewriting.md 800 | [terse composition]: ./goals.md#terse-composition 801 | [terse function application]: ./goals.md#terse-function-application 802 | [terse function calls]: ./goals.md#terse-function-calls 803 | [terse method extraction]: ./goals.md#terse-method-extraction 804 | [terse parentheses]: ./goals.md#terse-parentheses 805 | [terse partial application]: ./goals.md#terse-partial-application 806 | [terse variables]: ./goals.md#terse-variables 807 | [tertiary topic]: ./additional-feature-np.md 808 | [TheNavigateur functional composition]: https://github.com/TheNavigateur/proposal-pipeline-operator-for-function-composition 809 | [topic and comment]: https://en.wikipedia.org/wiki/Topic_and_comment 810 | [topic references in other programming languages]: ./relations.md#topic-references-in-other-programming-languages 811 | [topic style]: ./core-syntax.md#topic-style 812 | [topic variables in other languages]: https://rosettacode.org/wiki/Topic_variable 813 | [topic-token bikeshedding]: https://github.com/tc39/proposal-pipeline-operator/issues/91 814 | [Underscore.js + CP + BP + PP]: ./additional-feature-pp.md#underscorejs-core-proposal--additional-feature-bppp 815 | [Underscore.js + CP]: ./core-real-examples.md#underscorejs 816 | [Underscore.js]: http://underscorejs.org 817 | [Unix pipe]: https://en.wikipedia.org/wiki/Pipeline_(Unix 818 | [untangled flow]: ./goals.md#untangled-flow 819 | [Visual Basic’s `select` statement]: https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/select-case-statement 820 | [WebKit console variables]: https://webkit.org/blog/829/web-inspector-updates/ 821 | [WHATWG Fetch + CP]: ./core-real-examples.md#whatwg-fetch-standard 822 | [WHATWG Fetch Standard]: https://fetch.spec.whatwg.org/ 823 | [WHATWG Streams + CP + BP + PF + NP]: ./additional-feature-np.md#whatwg-streams-standard-core-proposal--additional-features-bppfmt 824 | [WHATWG Streams + CP + BP + PF]: ./additional-feature-pf.md#whatwg-streams-standard-core-proposal--additional-feature-bppf 825 | [WHATWG Streams Standard]: https://stream.spec.whatwg.org/ 826 | [WHATWG-stream piping]: https://streams.spec.whatwg.org/#pipe-chains 827 | [Wikipedia: term rewriting]: https://en.wikipedia.org/wiki/Term_rewriting 828 | [zero runtime cost]: ./goals.md#zero-runtime-cost 829 | -------------------------------------------------------------------------------- /core-syntax.md: -------------------------------------------------------------------------------- 1 | # Core-proposal syntax 2 | ECMAScript Stage-0 Proposal. Living Document. J. S. Choi, 2018-12. 3 | 4 | Most pipeline steps will use topic references in their steps. This style of 5 | pipeline step is called **[topic style][]**. 6 | 7 | For three simple cases – unary functions, unary async functions, and unary 8 | constructors – you may omit the topic reference from the pipeline step. This is 9 | called **[bare style][]**. 10 | 11 | When a pipe is in bare style, we refer to the pipeline as a **bare function 12 | call**. The step acts as just a simple reference to a function, such as with `… |> capitalize` or 13 | with `… |> console.log`. The step’s value would then be called as a unary 14 | function, without having to use the topic reference as an explicit argument. 15 | 16 | The two bare-style productions require no parameters, because they can only be 17 | **simple references**, made up of identifiers and dots `.`. (There are optional 18 | [Additional Features](./readme.md#additional-features) that extend these style in 19 | limited ways for further convenience. These Additional Features are not part of this 20 | Core Proposal but rather show possible future extensions.) 21 | 22 | | Valid [topic style][] | Valid [bare style][] | Invalid pipeline 23 | | ----------------------- | ---------------------------------------- | -------------------- 24 | |`… \|> f(#)` |`… \|> f` | `… \|> f()` 🚫 25 | | ″″ | ″″ | `… \|> (f)` 🚫 26 | | ″″ | ″″ | `… \|> (f())` 🚫 27 | |`… \|> o.f(#)` |`… \|> o.f` | `… \|> o.f()` 🚫 28 | |`… \|> o.f(arg, #)` |`const f = $ => o::f(arg, $); … \|> f` | `… \|> o.f(arg)` 🚫 29 | |`… \|> o.make()(#)` |`const f = o.make(); … \|> f` | `… \|> o.make()` 🚫 30 | |`… \|> o[symbol](#)` |`const f = o[symbol]; … \|> f` | `… \|> o[symbol]` 🚫 31 | 32 | ## Bare style 33 | The **bare style** supports using simple identifiers, possibly with chains of 34 | simple property identifiers. If there are any operators, parentheses (including 35 | for method calls), brackets, or anything other than identifiers and dot 36 | punctuators, then it is in [topic style][], not in bare style. 37 | 38 | If the pipeline step is a merely a simple reference, then that identifier is 39 | interpreted to be a **bare function call**. The pipeline’s value will be the 40 | result of evaluating the step as an identifier or member expression, then 41 | calling the result as a function, with the current topics as its arguments. 42 | 43 | That is: **if a pipeline** is of the form\ 44 | **_topic_ `|>` _identifier_**\ 45 | or **_topic_ `|>` _identifier0_`.`_identifier1_**\ 46 | or **_topic_ `|>` _identifier0_`.`_identifier1_`.`_identifier2_**\ 47 | or so forth,\ 48 | then the pipeline is a bare function call. 49 | 50 | ## Topic style 51 | The presence or absence of topic tokens (`#`, `##`, `###`) is *not* used in the 52 | grammar to distinguish topic style from bare style to fulfill the goal of 53 | [syntactic locality][]. Instead, **if a pipeline step** of the form 54 | |> _step_ does ***not* match the [bare style][]** (that is, it is *not* a bare 55 | function call, bare async function call, or bare constructor call), then it 56 | **must be in topic style**. Topic style **requires** that there be a topic 57 | reference in the pipeline step; otherwise it is an [early error][]. 58 | 59 | A pipeline step that is not in bare style is usually a **topic expression**. 60 | This is any expression at the [precedence level once tighter than pipeline-level 61 | expressions][operator precedence] – that is, any conditional-level expression. 62 | 63 | ## Practical consequences 64 | Therefore, a pipeline step in **[bare style][] *never*** contains **parentheses `(…)` or 65 | brackets `[…]`**. Neither `… |> object.method()` nor 66 | `… |> object.method(arg)` nor `… |> object[symbol]` nor `… |> object.createFunction()` 67 | are in bare style (in fact, they all are Syntax Errors, due to their being in 68 | [topic style][] without any topic references). 69 | 70 | **When a pipeline step needs parentheses or brackets**, then **don’t use bare style**, 71 | and instead **use a topic reference** in the step ([topic style][])…or **assign 72 | the step to a variable**, then **use that variable as a bare-style step**. 73 | 74 | # Operator precedence and associativity 75 | As a infix operation forming compound expressions, the [operator precedence and 76 | associativity][MDN operator precedence] of pipelining must be determined, relative 77 | to other operations. 78 | 79 | Precedence is tighter than arrow functions (`=>`), assignment (`=`, `+=`, …), 80 | generator `yield` and `yield *`, and sequence `,`; and it is looser than every 81 | other type of expression. If the pipe operation were any tighter than this 82 | level, its steps would have to be parenthesized for many frequent types of 83 | expressions. However, the result of a pipeline is also expected to often serve 84 | as the body of an arrow function or a variable assignment, so it is tighter than 85 | both types of expressions. 86 | 87 | All operation-precedence levels in JavaScript are listed here, from **tightest 88 | to loosest**. Each level may contain the parse types listed for that level – 89 | **as well as** any expression types from any precedence level that is listed 90 | **above** it. 91 | 92 | | Level | Type | Form | Associativity / fixity | 93 | | -------------- | ----------------------- | -------------- | ------------------------ | 94 | | Primary | This |`this` | Nullary | 95 | | ″″ | **[Primary topic][]** |**`#`** | ″″ | 96 | | ″″ | **[Secondary topic][]** |**`##`** | ″″ | 97 | | ″″ | **[Tertiary topic][]** |**`###`** | ″″ | 98 | | ″″ | **[Rest topic][]** |**`...`** | ″″ | 99 | | ″″ | Identifiers |`a` … | ″″ | 100 | | ″″ | Null |`null` | ″″ | 101 | | ″″ | Booleans |`true` `false` | ″″ | 102 | | ″″ | Numerics |`0` … | ″″ | 103 | | ″″ | Arrays |`[…]` | Circumfix | 104 | | ″″ | Object |`{…}` | ″″ | 105 | | ″″ | Function |`function (…) {…}`| ″″ | 106 | | ″″ | Classes |`class … {…}` | ″″ | 107 | | ″″ | Generators |`function * (…) {…}`| ″″ | 108 | | ″″ | Async functions |`async function (…) {…}`| ″″ | 109 | | ″″ | Regular expression |`/…/…` | ″″ | 110 | | ″″ | Templates |`` …`…` `` | ″″ | 111 | | ″″ | Parentheses |`(…)` | Circumfix | 112 | | LHS | Static properties |`….…` | ″″ | 113 | | ″″ | Dynamic properties |`…[…]` | LTR infix with circumfix | 114 | | ″″ | Tagged templates |`` …`…` `` | Unchainable infix with circumfix| 115 | | ″″ | Super call op.s |`super(…)` | Unchainable prefix | 116 | | ″″ | Super properties |`super.…` | ″″ | 117 | | ″″ | Meta properties |`meta.…` | ″″ | 118 | | ″″ | Object construction |`new …` | Prefix | 119 | | ″″ | Function call |`…(…)` | LTR infix with circumfix | 120 | | Postfix unary | Postfix incrementing |`…++` | Postfix | 121 | | ″″ | Postfix decrementing |`…--` | ″″ | 122 | | Prefix unary | Prefix incrementing |`++…` | RTL prefix | 123 | | Prefix unary | Prefix decrementing |`--…` | ″″ | 124 | | ″″ | Deletes |`delete …` | ″″ | 125 | | ″″ | Voids |`void …` | ″″ | 126 | | ″″ | Unary `+`/`-` |`+…` | ″″ | 127 | | ″″ | Bitwise NOT `~…` |`~…` | ″″ | 128 | | ″″ | Logical NOT `!…` |`!…` | ″″ | 129 | | ″″ | Awaiting |`await …` | ″″ | 130 | | Exponentiation | Exponentiation |`… ** …` | RTL infix | 131 | | Multiplicative | Multiplication |`… * …` | LTR infix | 132 | | ″″ | Division |`… / …` | ″″ | 133 | | ″″ | Modulus |`… % …` | ″″ | 134 | | Additive | Addition |`… + …` | ″″ | 135 | | ″″ | Subtraction |`… - …` | ″″ | 136 | | Bitwise shift | Left shift |`… << …` | ″″ | 137 | | ″″ | Right shift |`… >> …` | ″″ | 138 | | ″″ | Signed right shift |`… >> …` | ″″ | 139 | | Relational | Greater than |`… < …` | ″″ | 140 | | ″″ | Less than |`… > …` | ″″ | 141 | | ″″ | Greater than / equal to |`… >= …` | ″″ | 142 | | ″″ | Less than / equal to |`… <= …` | ″″ | 143 | | ″″ | Containment |`… in …` | ″″ | 144 | | ″″ | Instance-of |`… instanceof …`| ″″ | 145 | | Equality | Abstract equality |`… == …` | ″″ | 146 | | ″″ | Abstract inequality |`… != …` | ″″ | 147 | | ″″ | Strict equality |`… === …` | ″″ | 148 | | ″″ | Strict inequality |`… !== …` | ″″ | 149 | | Bitwise AND | |`… & …` | ″″ | 150 | | Bitwise XOR | |`… ^ …` | ″″ | 151 | | Bitwise OR | |`… \| …` | ″″ | 152 | | Logical AND | |`… ^^ …` | ″″ | 153 | | Logical OR | |`… \|\| …` | ″″ | 154 | | Conditional | |`… ? … : …` | RTL ternary infix | 155 | | Pipeline | **[Pipelines][]** |**`… \|> …`** | LTR infix | 156 | | Assignment | **[Pipeline functions][]**|**`+> …`** | Prefix | 157 | | ″″ | **[Async pipeline functions][]**|**`async +> …`**|Prefix | 158 | | ″″ | Arrow functions |`… => …` | RTL infix | 159 | | ″″ | Async arrow functions |`async … => …` | RTL infix | 160 | | ″″ | Assignment |`… = …` | ″″ | 161 | | ″″ | |`… += …` | ″″ | 162 | | ″″ | |`… -= …` | ″″ | 163 | | ″″ | |`… *= …` | ″″ | 164 | | ″″ | |`… %= …` | ″″ | 165 | | ″″ | |`… **= …` | ″″ | 166 | | ″″ | |`… <<= …` | ″″ | 167 | | ″″ | |`… >>= …` | ″″ | 168 | | ″″ | |`… >>>= …` | ″″ | 169 | | ″″ | |`… &= …` | ″″ | 170 | | ″″ | |`… \|= …` | ″″ | 171 | | Yield | Yielding |`yield …` | Prefix | 172 | | ″″ | Flat yielding |`yield * …` | ″″ | 173 | | ″″ | Spreading |`...…` | ″″ | 174 | | Comma level | Comma |`…, …` | LTR infix | 175 | | Base statements| Expression statements |`…;` | Postfix with [ASI][] | 176 | | ″″ | Empty statements |`;` | Nullary with [ASI][] | 177 | | ″″ | Debugger statements |`debugger;` | ″″ | 178 | | ″″ | Block statements |`{…}` | Circumfix | 179 | | ″″ | Labelled statements |`…: …` | Prefix | 180 | | ″″ | Continue statements |`continue …;` | Circumfix with [ASI][] | 181 | | ″″ | Break statements |`break …;` | ″″ | 182 | | ″″ | Return statements |`return …;` | ″″ | 183 | | ″″ | Throw statements |`throw …;` | ″″ | 184 | | ″″ | Variable statements |`var …;` | ″″ | 185 | | ″″ | Lexical declarations |`let …;` | ″″ | 186 | | ″″ | ″″ |`const …;` | ″″ | 187 | | ″″ | Hoistable declarations |`function … (…) {…}`| Circumfix with prefix| 188 | | ″″ | ″″ |`async function … (…) {…}`| ″″ | 189 | | ″″ | ″″ |`function * … (…) {…}`| ″″ | 190 | | ″″ | ″″ |`async function * … (…) {…}`| ″″ | 191 | | ″″ | Class declarations |`class … {…}` | ″″ | 192 | | Compound statements| If statements |`if (…) … else …`| Circumfix with prefix | 193 | | ″″ | Switch statements |`switch (…) …` | ″″ | 194 | | ″″ | Iteration statements | | ″″ | 195 | | ″″ | With statements |`with (…) {…}` | ″″ | 196 | | ″″ | Try statements |`try {…} catch (…) {…} finally {…}` | ″″ | 197 | | Statement list | Case clause |`case: …` | Unchainable prefix | 198 | | Root | Script | | Root | 199 | | ″″ | Module | | ″″ | 200 | 201 | ["data-to-ink" visual ratio]: https://www.darkhorseanalytics.com/blog/data-looks-better-naked 202 | ["don’t break my code"]: ./goals.md#dont-break-my-code 203 | ["don’t make me overthink"]: ./goals.md#dont-make-me-overthink 204 | ["don’t shoot me in the foot"]: ./goals.md#dont-shoot-me-in-the-foot 205 | ["make my code easier to read"]: ./goals.md#make-my-code-easier-to-read 206 | [`??:`]: https://github.com/tc39/proposal-nullish-coalescing/pull/23 207 | [`do` expression]: ./relations.md#do-expressions 208 | [`do` expressions]: ./relations.md#do-expressions 209 | [`for` iteration statements]: https://tc39.github.io/ecma262/#sec-iteration-statements 210 | [`in` relational operator]: https://tc39.github.io/ecma262/#sec-relational-operators 211 | [`match` expressions]: ./relations.md#pattern-matching 212 | [`new.target`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new.target 213 | [Additional Feature BA]: ./additional-feature-ba.md 214 | [Additional Feature BC]: ./additional-feature-bc.md 215 | [Additional Feature BP]: ./additional-feature-bp.md 216 | [Additional Feature NP]: ./additional-feature-np.md 217 | [Additional Feature PF]: ./additional-feature-pf.md 218 | [Additional Feature TS]: ./additional-feature-ts.md 219 | [additional features]: ./readme.md#additional-features 220 | [annevk]: https://github.com/annevk 221 | [antecedent]: https://en.wikipedia.org/wiki/Antecedent_(grammar) 222 | [arbitrary associativity]: ./goals.md#arbitrary-associativity 223 | [ASI]: https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion 224 | [associative property]: https://en.wikipedia.org/wiki/Associative_property 225 | [async pipeline functions]: ./additional-feature-pf.md 226 | [Babel plugin]: https://github.com/valtech-nyc/babel/ 227 | [Babel update summary]: https://github.com/babel/proposals/issues/29#issuecomment-372828328 228 | [background]: ./readme.md 229 | [backward compatibility]: ./goals.md#backward-compatibility 230 | [bare awaited function call]: ./core-syntax.md#bare-style 231 | [bare constructor call]: ./core-syntax.md#bare-style 232 | [bare function call]: ./core-syntax.md#bare-style 233 | [bare style]: ./core-syntax.md#bare-style 234 | [binding]: https://en.wikipedia.org/wiki/Binding_(linguistics) 235 | [block parameters]: ./relations.md#block-parameters 236 | [Clojure compact function]: https://clojure.org/reference/reader#_dispatch 237 | [Clojure pipe]: https://clojuredocs.org/clojure.core/as-%3E 238 | [completion records]: https://timothygu.me/es-howto/#completion-records-and-shorthands 239 | [concatenative programming]: https://en.wikipedia.org/wiki/Concatenative_programming_language 240 | [conceptual generality]: ./goals.md#conceptual-generality 241 | [Core Proposal]: ./readme.md 242 | [core-real-examples.md]: ./core-real-examples.md 243 | [currying]: https://en.wikipedia.org/wiki/Currying 244 | [cyclomatic complexity]: https://en.wikipedia.org/wiki/Cyclomatic_complexity#Applications 245 | [cyclomatic simplicity]: ./goals.md#cyclomatic-simplicity 246 | [dataflow programming]: https://en.wikipedia.org/wiki/Dataflow_programming 247 | [distinguishable punctuators]: ./goals.md#distinguishable-punctuators 248 | [don’t break my code]: ./goals.md#dont-break-my-code 249 | [DSLs]: https://en.wikipedia.org/wiki/Domain-specific_language 250 | [early error rule]: ./goals.md#static-analyzability 251 | [early error rules]: ./goals.md#static-analyzability 252 | [early error]: ./goals.md#static-analyzability 253 | [early errors]: ./goals.md#static-analyzability 254 | [ECMAScript _Identifier Name_]: https://tc39.github.io/ecma262/#prod-IdentifierName 255 | [ECMAScript _Identifier Reference_]: https://tc39.github.io/ecma262/#prod-IdentifierReference 256 | [ECMAScript _Member Expression_]: https://tc39.github.io/ecma262/#prod-MemberExpression 257 | [ECMAScript § The Syntactic Grammar]: https://tc39.github.io/ecma262/#sec-syntactic-grammar 258 | [ECMAScript `new` operator, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-new-operator-runtime-semantics-evaluation 259 | [ECMAScript arrow functions, § SS: Contains]: https://tc39.github.io/ecma262/#sec-arrow-function-definitions-static-semantics-contains 260 | [ECMAScript Assignment-level Expressions]: https://tc39.github.io/ecma262/#sec-assignment-operators 261 | [ECMAScript block parameters]: https://github.com/samuelgoto/proposal-block-params 262 | [ECMAScript Blocks, § RS: Block Declaration Instantiation]: https://tc39.github.io/ecma262/#sec-blockdeclarationinstantiation 263 | [ECMAScript Blocks, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-block-runtime-semantics-evaluation 264 | [ECMAScript Declarative Environment Records]: https://tc39.github.io/ecma262/#sec-declarative-environment-records 265 | [ECMAScript function binding]: https://github.com/zenparsing/es-function-bind 266 | [ECMAScript Function Calls, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-function-calls-runtime-semantics-evaluation 267 | [ECMAScript Function Environment Records]: https://tc39.github.io/ecma262/#sec-function-environment-records 268 | [ECMAScript Functions and Classes § Generator Function Definitions]: https://tc39.github.io/ecma262/#sec-generator-function-definitions 269 | [ECMAScript Get This Environment]: https://tc39.github.io/ecma262/#sec-getthisenvironment 270 | [ECMAScript headless-arrow proposal]: https://bterlson.github.io/headless-arrows/ 271 | [ECMAScript Lexical Environments]: https://tc39.github.io/ecma262/#sec-lexical-environments 272 | [ECMAScript Lexical Grammar]: https://tc39.github.io/ecma262/#sec-ecmascript-language-lexical-grammar 273 | [ECMAScript LHS expressions]: https://tc39.github.io/ecma262/#sec-left-hand-side-expressions 274 | [ECMAScript Lists and Records]: https://tc39.github.io/ecma262/#sec-list-and-record-specification-type 275 | [ECMAScript Notational Conventions, § Algorithm Conventions]: https://tc39.github.io/ecma262/#sec-algorithm-conventions-abstract-operations 276 | [ECMAScript Notational Conventions, § Grammars]: https://tc39.github.io/ecma262/#sec-syntactic-and-lexical-grammars 277 | [ECMAScript Notational Conventions, § Lexical Grammar]: https://tc39.github.io/ecma262/#sec-lexical-and-regexp-grammars 278 | [ECMAScript Notational Conventions, § Runtime Semantics]: https://tc39.github.io/ecma262/#sec-runtime-semantics 279 | [ECMAScript optional `catch` binding]: https://github.com/tc39/proposal-optional-catch-binding 280 | [ECMAScript partial application]: https://github.com/tc39/proposal-partial-application 281 | [ECMAScript pattern matching]: https://github.com/tc39/proposal-pattern-matching 282 | [ECMAScript Primary Expressions]: https://tc39.github.io/ecma262/#prod-PrimaryExpression 283 | [ECMAScript Property Accessors, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-property-accessors-runtime-semantics-evaluation 284 | [ECMAScript Punctuators]: https://tc39.github.io/ecma262/#sec-punctuators 285 | [ECMAScript static semantic rules]: https://tc39.github.io/ecma262/#sec-static-semantic-rules 286 | [Elixir pipe]: https://hexdocs.pm/elixir/Kernel.html#%7C%3E/2 287 | [Elm pipe]: http://elm-lang.org/docs/syntax#infix-operators 288 | [essential complexity]: https://en.wikipedia.org/wiki/Essential_complexity 289 | [expressions and operators (MDN)]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators 290 | [expressive versatility]: ./goals.md#expressive-versatility 291 | [F# pipe]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/functions/index#function-composition-and-pipelining 292 | [first pipe-operator proposal]: https://github.com/tc39/proposal-pipeline-operator/blob/37119110d40226476f7af302a778bc981f606cee/README.md 293 | [footguns]: https://en.wiktionary.org/wiki/footgun 294 | [formal BA]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-ba 295 | [formal BC]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-bc 296 | [formal BP]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-bp 297 | [formal CP]: https://jschoi.org/18/es-smart-pipelines/spec#introduction 298 | [formal NP]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-np 299 | [formal PF]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-pf 300 | [formal pipeline specification]: https://jschoi.org/18/es-smart-pipelines/spec 301 | [formal TS]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-ts 302 | [forward compatibility]: ./goals.md#forward-compatibility 303 | [forward compatible]: ./goals.md#forward-compatibility 304 | [function bind operator `::`]: ./relations.md#function-bind-operator 305 | [function binding]: ./relations.md#function-binding 306 | [function composition]: ./relations.md#function-composition 307 | [functional programming]: https://en.wikipedia.org/wiki/Functional_programming 308 | [gajus functional composition]: https://github.com/gajus/babel-plugin-transform-function-composition 309 | [garden-path syntax]: https://en.wikipedia.org/wiki/Garden_path_sentence 310 | [GitHub issue tracker]: https://github.com/tc39/proposal-pipeline-operator/issues 311 | [goals]: ./goals.md 312 | [Hack pipe]: https://docs.hhvm.com/hack/operators/pipe-operator 313 | [Huffman coding]: https://en.wikipedia.org/wiki/Huffman_coding 314 | [human writability]: ./goals.md#human-writability 315 | [i-am-tom functional composition]: https://github.com/fantasyland/ECMAScript-proposals/issues/1#issuecomment-306243513 316 | [identity function]: https://en.wikipedia.org/wiki/Identity_function 317 | [IIFEs]: https://en.wikipedia.org/wiki/Immediately-invoked_function_expression 318 | [immutable objects]: https://en.wikipedia.org/wiki/Immutable_object 319 | [incidental complexity]: https://en.wikipedia.org/wiki/Incidental_complexity 320 | [intro]: readme.md 321 | [isiahmeadows functional composition]: https://github.com/isiahmeadows/function-composition-proposal 322 | [jashkenas]: https://github.com/jashkenas 323 | [jQuery + CP]: ./core-real-examples.md#jquery 324 | [jQuery]: https://jquery.com/ 325 | [jquery/src/core/access.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/access.js 326 | [jquery/src/core/init.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/init.js 327 | [jquery/src/core/parseHTML.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/parseHTML.js 328 | [JS Foundation]: https://js.foundation/ 329 | [Julia pipe]: https://docs.julialang.org/en/stable/stdlib/base/#Base.:|> 330 | [lexical topic]: https://jschoi.org/18/es-smart-pipelines/spec#sec-lexical-topics 331 | [lexically hygienic]: https://en.wikipedia.org/wiki/Hygienic_macro 332 | [littledan invitation]: https://github.com/tc39/proposal-pipeline-operator/issues/89#issuecomment-363853394 333 | [littledan]: https://github.com/littledan 334 | [LiveScript pipe]: http://livescript.net/#operators-piping 335 | [Lodash + CP + BP + PF]: ./additional-feature-pf.md#lodash-core-proposal--additional-feature-bppf 336 | [Lodash + CP + BP + PP + PF + NP]: ./additional-feature-np.md#lodash-core-proposal--additional-features-bppppfmt 337 | [Lodash + CP]: ./core-real-examples.md#lodash 338 | [Lodash]: https://lodash.com/ 339 | [mAAdhaTTah]: https://github.com/mAAdhaTTah/ 340 | [make my code easier to read]: ./goals.md#make-my-code-easier-to-read 341 | [MDN operator precedence]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence 342 | [MDN operator precedence]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table 343 | [method-extraction inline caching]: https://github.com/tc39/proposal-bind-operator/issues/46 344 | [mindeavor]: https://github.com/gilbert 345 | [mode errors]: https://en.wikipedia.org/wiki/Mode_(computer_interface)#Mode_errors 346 | [motivation]: ./readme.md 347 | [Node-stream piping]: https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options 348 | [Node.js `util.promisify`]: https://nodejs.org/api/util.html#util_util_promisify_original 349 | [nomenclature]: ./nomenclature.md 350 | [novice learnability]: ./goals.md#novice-learnability 351 | [nullish coalescing proposal]: https://github.com/tc39/proposal-nullish-coalescing/ 352 | [object initializers’ Computed Property Contains rule]: https://tc39.github.io/ecma262/#sec-object-initializer-static-semantics-computedpropertycontains 353 | [OCaml pipe]: http://blog.shaynefletcher.org/2013/12/pipelining-with-operator-in-ocaml.html 354 | [operator precedence]: ./core-syntax.md#operator-precedence-and-associativity 355 | [opt-in behavior]: ./goals.md#opt-in-behavior 356 | [optional `catch` binding]: ./relations.md#optional-catch-binding 357 | [optional-chaining syntax proposal]: https://github.com/tc39/proposal-optional-chaining 358 | [other browsers’ console variables]: https://www.andismith.com/blogs/2011/11/25-dev-tool-secrets/ 359 | [other ECMAScript proposals]: ./relations.md#other-ecmascript-proposals 360 | [other goals]: ./goals.md#other-goals 361 | [pattern matching]: ./relations.md#pattern-matching 362 | [partial function application]: ./goals.md#partial-function-application 363 | [PEP 20]: https://www.python.org/dev/peps/pep-0020/ 364 | [Perl 6 pipe]: https://docs.perl6.org/language/operators#infix_==> 365 | [Perl 6 topicization]: https://www.perl.com/pub/2002/10/30/topic.html/ 366 | [Perl 6’s given block]: https://docs.perl6.org/language/control#given 367 | [pipeline functions]: ./additional-feature-pf.md 368 | [Pipeline Proposal 1]: https://github.com/tc39/proposal-pipeline-operator/wiki#proposal-1-f-sharp-only 369 | [Pipeline Proposal 4]: https://github.com/tc39/proposal-pipeline-operator/wiki#proposal-4-smart-mix 370 | [pipeline syntax]: ./core-syntax.md 371 | [pipelines]: ./readme.md 372 | [previous pipeline-placeholder discussions]: https://github.com/tc39/proposal-pipeline-operator/issues?q=placeholder 373 | [primary topic]: ./readme.md 374 | [private class fields]: https://github.com/tc39/proposal-class-fields/ 375 | [pure functions]: https://en.wikipedia.org/wiki/Pure_function 376 | [R pipe]: https://cran.r-project.org/web/packages/magrittr/vignettes/magrittr.html 377 | [Ramda + CP + BP + PF + NP]: ./additional-feature-np.md#ramda-core-proposal--additional-features-bppfmt 378 | [Ramda + CP + BP + PF]: ./additional-feature-pf.md#ramda-core-proposal--additional-feature-bppf 379 | [Ramda wiki cookbook]: https://github.com/ramda/ramda/wiki/Cookbook 380 | [Ramda]: http://ramdajs.com/ 381 | [relations to other work]: ./relations.md 382 | [REPLs]: https://en.wikipedia.org/wiki/Read–eval–print_loop 383 | [rest topic]: ./additional-feature-np.md 384 | [reverse Polish notation]: https://en.wikipedia.org/wiki/Reverse_Polish_notation 385 | [robust method extraction]: https://github.com/tc39/proposal-pipeline-operator/issues/110#issuecomment-374367888 386 | [Ron Buckton]: https://github.com/rbuckton 387 | [secondary topic]: ./additional-feature-np.md 388 | [semantic clarity]: ./goals.md#semantic-clarity 389 | [simonstaton functional composition]: https://github.com/simonstaton/Function.prototype.compose-TC39-Proposal 390 | [simple scoping]: ./goals.md#simple-scoping 391 | [sindresorhus]: https://github.com/sindresorhus 392 | [smart step syntax]: ./core-syntax.md 393 | [smart pipelines]: ./readme.md#smart-pipelines 394 | [Standard Style]: https://standardjs.com/ 395 | [static analyzability]: ./goals.md#static-analyzability 396 | [statically analyzable]: ./goals.md#static-analyzability 397 | [statically detectable early errors]: ./goals.md#static-analyzability 398 | [syntactic locality]: ./goals.md#syntactic-locality 399 | [tacit programming]: https://en.wikipedia.org/wiki/Tacit_programming 400 | [TC39 60th meeting, pipelines]: https://tc39.github.io/tc39-notes/2017-09_sep-26.html#11iia-pipeline-operator 401 | [TC39 process]: https://tc39.github.io/process-document/ 402 | [tc39/proposal-decorators#30]: tc39/proposal-decorators#30 403 | [tc39/proposal-decorators#42]: tc39/proposal-decorators#42 404 | [tc39/proposal-decorators#60]: tc39/proposal-decorators#60 405 | [Tennent correspondence principle]: http://gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html 406 | [term rewriting]: ./term-rewriting.md 407 | [terse composition]: ./goals.md#terse-composition 408 | [terse function application]: ./goals.md#terse-function-application 409 | [terse function calls]: ./goals.md#terse-function-calls 410 | [terse method extraction]: ./goals.md#terse-method-extraction 411 | [terse parentheses]: ./goals.md#terse-parentheses 412 | [terse partial application]: ./goals.md#terse-partial-application 413 | [terse variables]: ./goals.md#terse-variables 414 | [tertiary topic]: ./additional-feature-np.md 415 | [TheNavigateur functional composition]: https://github.com/TheNavigateur/proposal-pipeline-operator-for-function-composition 416 | [topic and comment]: https://en.wikipedia.org/wiki/Topic_and_comment 417 | [topic references in other programming languages]: ./relations.md#topic-references-in-other-programming-languages 418 | [topic style]: ./core-syntax.md#topic-style 419 | [topic variables in other languages]: https://rosettacode.org/wiki/Topic_variable 420 | [topic-token bikeshedding]: https://github.com/tc39/proposal-pipeline-operator/issues/91 421 | [Underscore.js + CP + BP + PP]: ./additional-feature-pp.md#underscorejs-core-proposal--additional-feature-bppp 422 | [Underscore.js + CP]: ./core-real-examples.md#underscorejs 423 | [Underscore.js]: http://underscorejs.org 424 | [Unix pipe]: https://en.wikipedia.org/wiki/Pipeline_(Unix 425 | [untangled flow]: ./goals.md#untangled-flow 426 | [Visual Basic’s `select` statement]: https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/select-case-statement 427 | [WebKit console variables]: https://webkit.org/blog/829/web-inspector-updates/ 428 | [WHATWG Fetch + CP]: ./core-real-examples.md#whatwg-fetch-standard 429 | [WHATWG Fetch Standard]: https://fetch.spec.whatwg.org/ 430 | [WHATWG Streams + CP + BP + PF + NP]: ./additional-feature-np.md#whatwg-streams-standard-core-proposal--additional-features-bppfmt 431 | [WHATWG Streams + CP + BP + PF]: ./additional-feature-pf.md#whatwg-streams-standard-core-proposal--additional-feature-bppf 432 | [WHATWG Streams Standard]: https://stream.spec.whatwg.org/ 433 | [WHATWG-stream piping]: https://streams.spec.whatwg.org/#pipe-chains 434 | [Wikipedia: term rewriting]: https://en.wikipedia.org/wiki/Term_rewriting 435 | [zero runtime cost]: ./goals.md#zero-runtime-cost 436 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright © 2018 J. S. Choi. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the “Software”), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | **The Software is provided “as is”, without warranty of any kind, express or 16 | implied, including but not limited to the warranties of merchantability, 17 | fitness for a particular purpose and noninfringement. In no event shall the 18 | authors or copyright holders be liable for any claim, damages or other 19 | liability, whether in an action of contract, tort or otherwise, arising from, 20 | out of or in connection with the software or the use or other dealings in the 21 | Software.** 22 | -------------------------------------------------------------------------------- /nomenclature.md: -------------------------------------------------------------------------------- 1 | # Explanation of nomenclature 2 | The term [“**topic**” comes from linguistics][topic and comment] and have 3 | precedent in prior programming languages’ use of “topic variables”. 4 | 5 | The term “**topic-style pipeline**” is preferred to “**topic expression**” 6 | because, in the future, the topic concept could be extended to other syntaxes, 7 | as with [Additional Feature TS][], not just pipelines. 8 | 9 | In addition, “**input** values of a pipeline step” is preferred to “pipeline 10 | **LHS**”, because “LHS” in the ECMAScript specification usually refers to the 11 | [LHS of assignments][ECMAScript LHS expressions], which may be confusing. 12 | However, “LHS” is still a fine and acceptable, if not nonspecific, name for a 13 | pipeline step’s input. The **head** of a pipeline – the input of a pipeline’s 14 | first step – is distinguished from the pipeline itself. A pipeline head cannot 15 | contain any topic references, and it is completely omitted in [pipeline 16 | functions][]. 17 | 18 | The term “**topic reference**” is preferred to the phrase “**topic variable**” 19 | because the latter is a misnomer. The topic reference is *not* a variable 20 | identifier. Unlike variables, it cannot be manually declared (`const #` is a 21 | syntax error), nor can it be assigned with a value (`# = 3` is a syntax error). 22 | 23 | “Topic reference” is also preferred to “**topic placeholder**”, to avoid 24 | confusion with the placeholders of another TC39 proposal – [partial function 25 | application][]. These placeholders (currently denoted by nullary `?`) are of a 26 | different nature than topic references. Instead of referring to a single value 27 | bound earlier in the surrounding lexical context, these **parameter 28 | placeholders** act as the parameter to a new function. When this new function is 29 | called, those parameter placeholders will be bound to multiple argument values. 30 | 31 | The terms “**pipeline step**” and “**output** values of a pipeline step” is 32 | preferred instead of “**RHS** of a pipeline”, just as how “input values” is 33 | preferred to “LHS”. However, “RHS” is still a fine and acceptable name for the 34 | right-hand side of a pipe operator. The **step** is the expression itself; it 35 | evaluates into one or output values. The output values in turn either are fed 36 | into the following pipeline step as its inputs or become the value of the entire 37 | pipeline. (All pipelines are allowed to result in at most one output; it is an 38 | [early error][] if it could ever return zero or more than one outputs.) 39 | 40 | “**[Bare style][]**” could also be called “**tacit style**”, but the former is 41 | preferred to the latter. Eventually, certain possible future extensions to the 42 | topic concept, such as [Additional Feature TS][], would enable [tacit 43 | programming][] even without using bare-style pipelines. **Bare style** could 44 | also have been called **plain style**. 45 | 46 | ["data-to-ink" visual ratio]: https://www.darkhorseanalytics.com/blog/data-looks-better-naked 47 | ["don’t break my code"]: ./goals.md#dont-break-my-code 48 | ["don’t make me overthink"]: ./goals.md#dont-make-me-overthink 49 | ["don’t shoot me in the foot"]: ./goals.md#dont-shoot-me-in-the-foot 50 | ["make my code easier to read"]: ./goals.md#make-my-code-easier-to-read 51 | [`??:`]: https://github.com/tc39/proposal-nullish-coalescing/pull/23 52 | [`do` expression]: ./relations.md#do-expressions 53 | [`do` expressions]: ./relations.md#do-expressions 54 | [`for` iteration statements]: https://tc39.github.io/ecma262/#sec-iteration-statements 55 | [`in` relational operator]: https://tc39.github.io/ecma262/#sec-relational-operators 56 | [`match` expressions]: ./relations.md#pattern-matching 57 | [`new.target`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new.target 58 | [Additional Feature BA]: ./additional-feature-ba.md 59 | [Additional Feature BC]: ./additional-feature-bc.md 60 | [Additional Feature BP]: ./additional-feature-bp.md 61 | [Additional Feature NP]: ./additional-feature-np.md 62 | [Additional Feature PF]: ./additional-feature-pf.md 63 | [Additional Feature TS]: ./additional-feature-ts.md 64 | [additional features]: ./readme.md#additional-features 65 | [annevk]: https://github.com/annevk 66 | [antecedent]: https://en.wikipedia.org/wiki/Antecedent_(grammar) 67 | [arbitrary associativity]: ./goals.md#arbitrary-associativity 68 | [ASI]: https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion 69 | [associative property]: https://en.wikipedia.org/wiki/Associative_property 70 | [async pipeline functions]: ./additional-feature-pf.md 71 | [Babel plugin]: https://github.com/valtech-nyc/babel/ 72 | [Babel update summary]: https://github.com/babel/proposals/issues/29#issuecomment-372828328 73 | [background]: ./readme.md 74 | [backward compatibility]: ./goals.md#backward-compatibility 75 | [bare awaited function call]: ./core-syntax.md#bare-style 76 | [bare constructor call]: ./core-syntax.md#bare-style 77 | [bare function call]: ./core-syntax.md#bare-style 78 | [bare style]: ./core-syntax.md#bare-style 79 | [binding]: https://en.wikipedia.org/wiki/Binding_(linguistics) 80 | [block parameters]: ./relations.md#block-parameters 81 | [Clojure compact function]: https://clojure.org/reference/reader#_dispatch 82 | [Clojure pipe]: https://clojuredocs.org/clojure.core/as-%3E 83 | [completion records]: https://timothygu.me/es-howto/#completion-records-and-shorthands 84 | [concatenative programming]: https://en.wikipedia.org/wiki/Concatenative_programming_language 85 | [conceptual generality]: ./goals.md#conceptual-generality 86 | [Core Proposal]: ./readme.md 87 | [core-real-examples.md]: ./core-real-examples.md 88 | [currying]: https://en.wikipedia.org/wiki/Currying 89 | [cyclomatic complexity]: https://en.wikipedia.org/wiki/Cyclomatic_complexity#Applications 90 | [cyclomatic simplicity]: ./goals.md#cyclomatic-simplicity 91 | [dataflow programming]: https://en.wikipedia.org/wiki/Dataflow_programming 92 | [distinguishable punctuators]: ./goals.md#distinguishable-punctuators 93 | [don’t break my code]: ./goals.md#dont-break-my-code 94 | [DSLs]: https://en.wikipedia.org/wiki/Domain-specific_language 95 | [early error rule]: ./goals.md#static-analyzability 96 | [early error rules]: ./goals.md#static-analyzability 97 | [early error]: ./goals.md#static-analyzability 98 | [early errors]: ./goals.md#static-analyzability 99 | [ECMAScript _Identifier Name_]: https://tc39.github.io/ecma262/#prod-IdentifierName 100 | [ECMAScript _Identifier Reference_]: https://tc39.github.io/ecma262/#prod-IdentifierReference 101 | [ECMAScript _Member Expression_]: https://tc39.github.io/ecma262/#prod-MemberExpression 102 | [ECMAScript § The Syntactic Grammar]: https://tc39.github.io/ecma262/#sec-syntactic-grammar 103 | [ECMAScript `new` operator, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-new-operator-runtime-semantics-evaluation 104 | [ECMAScript arrow functions, § SS: Contains]: https://tc39.github.io/ecma262/#sec-arrow-function-definitions-static-semantics-contains 105 | [ECMAScript Assignment-level Expressions]: https://tc39.github.io/ecma262/#sec-assignment-operators 106 | [ECMAScript block parameters]: https://github.com/samuelgoto/proposal-block-params 107 | [ECMAScript Blocks, § RS: Block Declaration Instantiation]: https://tc39.github.io/ecma262/#sec-blockdeclarationinstantiation 108 | [ECMAScript Blocks, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-block-runtime-semantics-evaluation 109 | [ECMAScript Declarative Environment Records]: https://tc39.github.io/ecma262/#sec-declarative-environment-records 110 | [ECMAScript function binding]: https://github.com/zenparsing/es-function-bind 111 | [ECMAScript Function Calls, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-function-calls-runtime-semantics-evaluation 112 | [ECMAScript Function Environment Records]: https://tc39.github.io/ecma262/#sec-function-environment-records 113 | [ECMAScript Functions and Classes § Generator Function Definitions]: https://tc39.github.io/ecma262/#sec-generator-function-definitions 114 | [ECMAScript Get This Environment]: https://tc39.github.io/ecma262/#sec-getthisenvironment 115 | [ECMAScript headless-arrow proposal]: https://bterlson.github.io/headless-arrows/ 116 | [ECMAScript Lexical Environments]: https://tc39.github.io/ecma262/#sec-lexical-environments 117 | [ECMAScript Lexical Grammar]: https://tc39.github.io/ecma262/#sec-ecmascript-language-lexical-grammar 118 | [ECMAScript LHS expressions]: https://tc39.github.io/ecma262/#sec-left-hand-side-expressions 119 | [ECMAScript Lists and Records]: https://tc39.github.io/ecma262/#sec-list-and-record-specification-type 120 | [ECMAScript Notational Conventions, § Algorithm Conventions]: https://tc39.github.io/ecma262/#sec-algorithm-conventions-abstract-operations 121 | [ECMAScript Notational Conventions, § Grammars]: https://tc39.github.io/ecma262/#sec-syntactic-and-lexical-grammars 122 | [ECMAScript Notational Conventions, § Lexical Grammar]: https://tc39.github.io/ecma262/#sec-lexical-and-regexp-grammars 123 | [ECMAScript Notational Conventions, § Runtime Semantics]: https://tc39.github.io/ecma262/#sec-runtime-semantics 124 | [ECMAScript optional `catch` binding]: https://github.com/tc39/proposal-optional-catch-binding 125 | [ECMAScript partial application]: https://github.com/tc39/proposal-partial-application 126 | [ECMAScript pattern matching]: https://github.com/tc39/proposal-pattern-matching 127 | [ECMAScript Primary Expressions]: https://tc39.github.io/ecma262/#prod-PrimaryExpression 128 | [ECMAScript Property Accessors, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-property-accessors-runtime-semantics-evaluation 129 | [ECMAScript Punctuators]: https://tc39.github.io/ecma262/#sec-punctuators 130 | [ECMAScript static semantic rules]: https://tc39.github.io/ecma262/#sec-static-semantic-rules 131 | [Elixir pipe]: https://hexdocs.pm/elixir/Kernel.html#%7C%3E/2 132 | [Elm pipe]: http://elm-lang.org/docs/syntax#infix-operators 133 | [essential complexity]: https://en.wikipedia.org/wiki/Essential_complexity 134 | [expressions and operators (MDN)]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators 135 | [expressive versatility]: ./goals.md#expressive-versatility 136 | [F# pipe]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/functions/index#function-composition-and-pipelining 137 | [first pipe-operator proposal]: https://github.com/tc39/proposal-pipeline-operator/blob/37119110d40226476f7af302a778bc981f606cee/README.md 138 | [footguns]: https://en.wiktionary.org/wiki/footgun 139 | [formal BA]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-ba 140 | [formal BC]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-bc 141 | [formal BP]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-bp 142 | [formal CP]: https://jschoi.org/18/es-smart-pipelines/spec#introduction 143 | [formal NP]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-np 144 | [formal PF]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-pf 145 | [formal pipeline specification]: https://jschoi.org/18/es-smart-pipelines/spec 146 | [formal TS]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-ts 147 | [forward compatibility]: ./goals.md#forward-compatibility 148 | [forward compatible]: ./goals.md#forward-compatibility 149 | [function bind operator `::`]: ./relations.md#function-bind-operator 150 | [function binding]: ./relations.md#function-binding 151 | [function composition]: ./relations.md#function-composition 152 | [functional programming]: https://en.wikipedia.org/wiki/Functional_programming 153 | [gajus functional composition]: https://github.com/gajus/babel-plugin-transform-function-composition 154 | [garden-path syntax]: https://en.wikipedia.org/wiki/Garden_path_sentence 155 | [GitHub issue tracker]: https://github.com/tc39/proposal-pipeline-operator/issues 156 | [goals]: ./goals.md 157 | [Hack pipe]: https://docs.hhvm.com/hack/operators/pipe-operator 158 | [Huffman coding]: https://en.wikipedia.org/wiki/Huffman_coding 159 | [human writability]: ./goals.md#human-writability 160 | [i-am-tom functional composition]: https://github.com/fantasyland/ECMAScript-proposals/issues/1#issuecomment-306243513 161 | [identity function]: https://en.wikipedia.org/wiki/Identity_function 162 | [IIFEs]: https://en.wikipedia.org/wiki/Immediately-invoked_function_expression 163 | [immutable objects]: https://en.wikipedia.org/wiki/Immutable_object 164 | [incidental complexity]: https://en.wikipedia.org/wiki/Incidental_complexity 165 | [intro]: readme.md 166 | [isiahmeadows functional composition]: https://github.com/isiahmeadows/function-composition-proposal 167 | [jashkenas]: https://github.com/jashkenas 168 | [jQuery + CP]: ./core-real-examples.md#jquery 169 | [jQuery]: https://jquery.com/ 170 | [jquery/src/core/access.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/access.js 171 | [jquery/src/core/init.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/init.js 172 | [jquery/src/core/parseHTML.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/parseHTML.js 173 | [JS Foundation]: https://js.foundation/ 174 | [Julia pipe]: https://docs.julialang.org/en/stable/stdlib/base/#Base.:|> 175 | [lexical topic]: https://jschoi.org/18/es-smart-pipelines/spec#sec-lexical-topics 176 | [lexically hygienic]: https://en.wikipedia.org/wiki/Hygienic_macro 177 | [littledan invitation]: https://github.com/tc39/proposal-pipeline-operator/issues/89#issuecomment-363853394 178 | [littledan]: https://github.com/littledan 179 | [LiveScript pipe]: http://livescript.net/#operators-piping 180 | [Lodash + CP + BP + PF]: ./additional-feature-pf.md#lodash-core-proposal--additional-feature-bppf 181 | [Lodash + CP + BP + PP + PF + NP]: ./additional-feature-np.md#lodash-core-proposal--additional-features-bppppfmt 182 | [Lodash + CP]: ./core-real-examples.md#lodash 183 | [Lodash]: https://lodash.com/ 184 | [mAAdhaTTah]: https://github.com/mAAdhaTTah/ 185 | [make my code easier to read]: ./goals.md#make-my-code-easier-to-read 186 | [MDN operator precedence]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence 187 | [MDN operator precedence]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table 188 | [method-extraction inline caching]: https://github.com/tc39/proposal-bind-operator/issues/46 189 | [mindeavor]: https://github.com/gilbert 190 | [mode errors]: https://en.wikipedia.org/wiki/Mode_(computer_interface)#Mode_errors 191 | [motivation]: ./readme.md 192 | [Node-stream piping]: https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options 193 | [Node.js `util.promisify`]: https://nodejs.org/api/util.html#util_util_promisify_original 194 | [nomenclature]: ./nomenclature.md 195 | [novice learnability]: ./goals.md#novice-learnability 196 | [nullish coalescing proposal]: https://github.com/tc39/proposal-nullish-coalescing/ 197 | [object initializers’ Computed Property Contains rule]: https://tc39.github.io/ecma262/#sec-object-initializer-static-semantics-computedpropertycontains 198 | [OCaml pipe]: http://blog.shaynefletcher.org/2013/12/pipelining-with-operator-in-ocaml.html 199 | [operator precedence]: ./core-syntax.md#operator-precedence-and-associativity 200 | [opt-in behavior]: ./goals.md#opt-in-behavior 201 | [optional `catch` binding]: ./relations.md#optional-catch-binding 202 | [optional-chaining syntax proposal]: https://github.com/tc39/proposal-optional-chaining 203 | [other browsers’ console variables]: https://www.andismith.com/blogs/2011/11/25-dev-tool-secrets/ 204 | [other ECMAScript proposals]: ./relations.md#other-ecmascript-proposals 205 | [other goals]: ./goals.md#other-goals 206 | [pattern matching]: ./relations.md#pattern-matching 207 | [partial function application]: ./goals.md#partial-function-application 208 | [PEP 20]: https://www.python.org/dev/peps/pep-0020/ 209 | [Perl 6 pipe]: https://docs.perl6.org/language/operators#infix_==> 210 | [Perl 6 topicization]: https://www.perl.com/pub/2002/10/30/topic.html/ 211 | [Perl 6’s given block]: https://docs.perl6.org/language/control#given 212 | [pipeline functions]: ./additional-feature-pf.md 213 | [Pipeline Proposal 1]: https://github.com/tc39/proposal-pipeline-operator/wiki#proposal-1-f-sharp-only 214 | [Pipeline Proposal 4]: https://github.com/tc39/proposal-pipeline-operator/wiki#proposal-4-smart-mix 215 | [pipeline syntax]: ./core-syntax.md 216 | [pipelines]: ./readme.md 217 | [previous pipeline-placeholder discussions]: https://github.com/tc39/proposal-pipeline-operator/issues?q=placeholder 218 | [primary topic]: ./readme.md 219 | [private class fields]: https://github.com/tc39/proposal-class-fields/ 220 | [pure functions]: https://en.wikipedia.org/wiki/Pure_function 221 | [R pipe]: https://cran.r-project.org/web/packages/magrittr/vignettes/magrittr.html 222 | [Ramda + CP + BP + PF + NP]: ./additional-feature-np.md#ramda-core-proposal--additional-features-bppfmt 223 | [Ramda + CP + BP + PF]: ./additional-feature-pf.md#ramda-core-proposal--additional-feature-bppf 224 | [Ramda wiki cookbook]: https://github.com/ramda/ramda/wiki/Cookbook 225 | [Ramda]: http://ramdajs.com/ 226 | [relations to other work]: ./relations.md 227 | [REPLs]: https://en.wikipedia.org/wiki/Read–eval–print_loop 228 | [rest topic]: ./additional-feature-np.md 229 | [reverse Polish notation]: https://en.wikipedia.org/wiki/Reverse_Polish_notation 230 | [robust method extraction]: https://github.com/tc39/proposal-pipeline-operator/issues/110#issuecomment-374367888 231 | [Ron Buckton]: https://github.com/rbuckton 232 | [secondary topic]: ./additional-feature-np.md 233 | [semantic clarity]: ./goals.md#semantic-clarity 234 | [simonstaton functional composition]: https://github.com/simonstaton/Function.prototype.compose-TC39-Proposal 235 | [simple scoping]: ./goals.md#simple-scoping 236 | [sindresorhus]: https://github.com/sindresorhus 237 | [smart step syntax]: ./core-syntax.md 238 | [smart pipelines]: ./readme.md#smart-pipelines 239 | [Standard Style]: https://standardjs.com/ 240 | [static analyzability]: ./goals.md#static-analyzability 241 | [statically analyzable]: ./goals.md#static-analyzability 242 | [statically detectable early errors]: ./goals.md#static-analyzability 243 | [syntactic locality]: ./goals.md#syntactic-locality 244 | [tacit programming]: https://en.wikipedia.org/wiki/Tacit_programming 245 | [TC39 60th meeting, pipelines]: https://tc39.github.io/tc39-notes/2017-09_sep-26.html#11iia-pipeline-operator 246 | [TC39 process]: https://tc39.github.io/process-document/ 247 | [tc39/proposal-decorators#30]: tc39/proposal-decorators#30 248 | [tc39/proposal-decorators#42]: tc39/proposal-decorators#42 249 | [tc39/proposal-decorators#60]: tc39/proposal-decorators#60 250 | [Tennent correspondence principle]: http://gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html 251 | [term rewriting]: ./term-rewriting.md 252 | [terse composition]: ./goals.md#terse-composition 253 | [terse function application]: ./goals.md#terse-function-application 254 | [terse function calls]: ./goals.md#terse-function-calls 255 | [terse method extraction]: ./goals.md#terse-method-extraction 256 | [terse parentheses]: ./goals.md#terse-parentheses 257 | [terse partial application]: ./goals.md#terse-partial-application 258 | [terse variables]: ./goals.md#terse-variables 259 | [tertiary topic]: ./additional-feature-np.md 260 | [TheNavigateur functional composition]: https://github.com/TheNavigateur/proposal-pipeline-operator-for-function-composition 261 | [topic and comment]: https://en.wikipedia.org/wiki/Topic_and_comment 262 | [topic references in other programming languages]: ./relations.md#topic-references-in-other-programming-languages 263 | [topic style]: ./core-syntax.md#topic-style 264 | [topic variables in other languages]: https://rosettacode.org/wiki/Topic_variable 265 | [topic-token bikeshedding]: https://github.com/tc39/proposal-pipeline-operator/issues/91 266 | [Underscore.js + CP + BP + PP]: ./additional-feature-pp.md#underscorejs-core-proposal--additional-feature-bppp 267 | [Underscore.js + CP]: ./core-real-examples.md#underscorejs 268 | [Underscore.js]: http://underscorejs.org 269 | [Unix pipe]: https://en.wikipedia.org/wiki/Pipeline_(Unix 270 | [untangled flow]: ./goals.md#untangled-flow 271 | [Visual Basic’s `select` statement]: https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/select-case-statement 272 | [WebKit console variables]: https://webkit.org/blog/829/web-inspector-updates/ 273 | [WHATWG Fetch + CP]: ./core-real-examples.md#whatwg-fetch-standard 274 | [WHATWG Fetch Standard]: https://fetch.spec.whatwg.org/ 275 | [WHATWG Streams + CP + BP + PF + NP]: ./additional-feature-np.md#whatwg-streams-standard-core-proposal--additional-features-bppfmt 276 | [WHATWG Streams + CP + BP + PF]: ./additional-feature-pf.md#whatwg-streams-standard-core-proposal--additional-feature-bppf 277 | [WHATWG Streams Standard]: https://stream.spec.whatwg.org/ 278 | [WHATWG-stream piping]: https://streams.spec.whatwg.org/#pipe-chains 279 | [Wikipedia: term rewriting]: https://en.wikipedia.org/wiki/Term_rewriting 280 | [zero runtime cost]: ./goals.md#zero-runtime-cost 281 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "proposal-smart-pipelines", 4 | "description": "Draft specification for smart pipelines.", 5 | "author": "J. S. Choi (https://jschoi.org/)", 6 | "license": "MIT", 7 | "repository": "js-choi/proposal-smart-pipelines", 8 | "scripts": { 9 | "prespec": "mkdir -p out/", 10 | "spec": "ecmarkup spec.html out/index.html --assets inline --contributors \"J. S. Choi, Ecma International\" --copyright true --title \"Smart Pipelines\" --status \"proposal\" --stage 0", 11 | "prewatch": "mkdir -p out/", 12 | "watch": "npm run spec -- --watch" 13 | }, 14 | "devDependencies": { 15 | "ecmarkup": "^4.0.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /term-rewriting.md: -------------------------------------------------------------------------------- 1 | # Term rewriting 2 | Living Document. J. S. Choi, 2018-12. 3 | 4 | ## Core Proposal 5 | Pipelines can be rewritten into a nested [`do` expression][]. There are 6 | many ways to illustrate this equivalency. (It can also be less simply rewritten 7 | without `do` expressions.) The simplest way is to use a single `do` expression 8 | containing a series of autogenerated variable declarations, in which the 9 | variables are arbitrary except they are [lexically hygienic][]: that is, the 10 | variables can be anything as long as they do not conflict with other 11 | already-existing variables. 12 | 13 | With this notation, each line in this example would be equivalent to all the 14 | other lines. 15 | ```js 16 | 1 |> # + 2 |> # * 3; 17 | 18 | // Static term rewriting 19 | do { const _0 = 1, _1 = _0 + 2; _1 * 3; }; 20 | 21 | // Runtime evaluation 22 | do { const _1 = 1 + 2; _1 * 3; }; 23 | do { 3 * 3; }; 24 | 9; 25 | ``` 26 | 27 | Consider also the [motivating first example above][Core Proposal]: 28 | ```js 29 | promise 30 | |> await # 31 | |> # || throw new TypeError( 32 | `Invalid value from ${promise}`) 33 | |> doubleSay(#, ', ') 34 | |> capitalize 35 | |> # + '!' 36 | |> new User.Message(#) 37 | |> await stream.write(#) 38 | |> console.log; 39 | ``` 40 | 41 | This would be statically equivalent to the following: 42 | ```js 43 | do { 44 | const 45 | _0 = promise, 46 | _1 = await _0, 47 | _2 = _1 || throw new TypeError( 48 | `Invalid value from ${promise}`), 49 | _3 = doubleSay(_2), 50 | _4 = capitalize(_3); 51 | _5 = _4 + '!', 52 | _6 = new User.Message(_5), 53 | _7 = await stream.write(_6); 54 | console.log(_7); 55 | } 56 | ``` 57 | Suppose that we can generate a series of new [lexically hygienic][] variables 58 | (`_0`, `_1`, `_2`, `_3`, …). Each autogenerated variable will replace every 59 | topic reference `#` in each consecutive pipeline step. These `_n` variables 60 | need only be unique within their lexical scopes: they must not shadow any 61 | outer lexical environment’s variable, and they must not be shadowed by any 62 | deeply inner lexical environment’s variable. 63 | 64 | With this notation, then in general, given a pipeline:\ 65 | 𝐸₀ `|>` 𝐸₁ `|>` 𝐸₂ `|>` … `|>` 𝐸ᵤ₋₂ `|>` 𝐸ᵤ₋₁,\ 66 | …then that pipeline is equivalent to:\ 67 | `do` `{`\ 68 |   `const `\ 69 |     #₀ `=` 𝐸₀ `,`\ 70 |     #₁ `=` sub(𝐸₁, #₀) `,`\ 71 |     #₂ `=` sub(𝐸₂, #₁) `,`\ 72 |     … `,`\ 73 |     #ᵤ₋₂ `=` sub(𝐸ᵤ₋₂, #ᵤ₋₃) `;`\ 74 |   sub(𝐸ᵤ₋₁, #ᵤ₋₂) `;`\ 75 | `}`,\ 76 | 77 | * If 𝑃 is a [bare function call][] – then sub(𝑃, #) is 𝑃 `(` # `)`. 78 | * If 𝑃 is a [bare awaited function call][] – then sub(𝑃, #) is 79 | `await` 𝑃 `(` # `)`. 80 | * If 𝑃 is a [bare constructor call][] – then sub(𝑃, #) is `new` 𝑃 `(` # `)`. 81 | * If 𝑃 is in [topic style][] – then sub(𝑃, #) is 𝑃 but in which all unshadowed 82 | instances of the topic reference `#` are replaced by #. 83 | 84 | ## Additional Feature BP 85 | Using the same notation from the first subsection, then in general: 86 | 87 | * If 𝑃 is a [bare function call][] – then sub(𝑃, #) is 𝑃 `(` # `)`. 88 | * If 𝑃 is a [bare awaited function call][] – then sub(𝑃, #) is 89 | `await` 𝑃 `(` # `)`. 90 | * If 𝑃 is a [bare constructor call][] – then sub(𝑃, #) is `new` 𝑃 `(` # `)`. 91 | * If 𝑃 is in [topic style][] – then sub(𝑃, #) is 𝑃 but in which all unshadowed 92 | instances of the topic reference `#` are replaced by #. 93 | * **If 𝑃 is in the form `{` 𝑆₀ `;` 𝑆₁ `;` … `;` 𝑆ᵥ₋₂ `;` 𝑆ᵥ₋₁ `;` `}` – then sub(𝑃, #) is 94 | `do {` sub(𝑆₀, #) `;` sub(𝑆₁, #) `;` … `;` sub(𝑆ᵥ₋₂, #) `;` sub(𝑆ᵥ₋₁, #) `;` `}`**. 95 | 96 | ## Additional Feature NP 97 | Adapted from a [previous example][Additional Feature NP]: 98 | ```js 99 | x = (a, b, ...c, d, e) 100 | |> f(##, x, ...) 101 | |> g; 102 | ``` 103 | This would be statically equivalent to the following: 104 | ```js 105 | x = do { 106 | const 107 | [_0, __0, ...s_0] = [a, b, ...c, d, e] 108 | _1 = f(__0, x, ...s_0); 109 | g(_1); 110 | }; 111 | ``` 112 | 113 | Another one: 114 | ```js 115 | x = (a, b) 116 | |> (f, # ** c + ##) 117 | |> # - ## 118 | |> g; 119 | ``` 120 | This would be statically equivalent to the following: 121 | ```js 122 | x = do { 123 | const 124 | [_0, __0] = [a, b] 125 | [_1, __1] = [f(_0), _0 ** c + __0]; 126 | _2 = _1 - __1; 127 | g(_2); 128 | }; 129 | ``` 130 | 131 | From a [previous Lodash example][Lodash + CP + BP + PP + PF + NP]: 132 | ```js 133 | x = number 134 | |> `${#}e` 135 | |> ...#.split('e') 136 | |> `${#}e${+## + precision}` 137 | |> func; 138 | ``` 139 | This would be statically equivalent to the following: 140 | ```js 141 | x = do { 142 | const 143 | _0 = number, 144 | _1 = `${_0}e`, 145 | [_2, __2] = [..._1.split('e')]; 146 | func(_2, __2); 147 | }; 148 | ``` 149 | …which of course may be simplified to: 150 | ```js 151 | x = do { 152 | const 153 | _0 = number, 154 | _1 = `${_0}e`, 155 | [_2, __2] = [..._1.split('e')]; 156 | func(_2, __2); 157 | } 158 | ``` 159 | 160 | From a [previous WHATWG Streams example][WHATWG Streams + CP + BP + PF + NP] 161 | with [Additional Feature BC][]: 162 | ```js 163 | x = value 164 | |> (#, offset, #.byteLength - offset) 165 | |> new Uint8Array 166 | |> await reader.read 167 | |> (#.buffer, #.byteLength) 168 | |> readInto(#, offset + ##); 169 | ``` 170 | This would be statically equivalent to the following: 171 | ```js 172 | x = do { 173 | const 174 | [_0] = [value], 175 | [_1, __1, ___1] = [_0, offset(_0), __0.byteLength - offset], 176 | _2 = new Uint8Array(_1), 177 | _3 = await reader.read(_2), 178 | [_4, __4] = [_3.buffer, _3.byteLength]; 179 | readInto(_4, offset + __4); 180 | }; 181 | ``` 182 | …which of course may be simplified to: 183 | ```js 184 | x = do { 185 | const 186 | _0 = value, 187 | _1 = _0, 188 | __1 = offset, 189 | ___1 = _0.byteLength - offset, 190 | _2 = new Uint8Array(_1), 191 | _3 = await reader.read(_2), 192 | _4 = _3.buffer, 193 | __4 = _3.byteLength; 194 | readInto(_4, offset + __4); 195 | } 196 | ``` 197 | 198 | Using the same notation from the first subsection, then consider any 199 | pipeline:\ 200 | 𝐸₀ `|>` 𝐸₁ `|>` 𝐸₂ `|>` … `|>` 𝐸ᵤ₋₂ `|>` 𝐸ᵤ₋₁\ 201 | …in which, for each i from 0 until n−1, 𝐸ᵢ is either: 202 | 203 | * A single expression 𝐸ᵢ[0] (which may start with `...`). 204 | * Or an argument list `(` 𝐸ᵢ[0] `,` 𝐸ᵢ[1] `,` … `,` 𝐸ᵢ[width(𝐸ᵢ)−2] `,` 205 | 𝐸ᵢ[width(𝐸ᵢ)−1] `)`, where each element of the argument list may be an 206 | expression, an expression starting with `...`, or a blank elision. 207 | 208 | The last pipeline step, 𝐸ᵤ₋₁, is an exception: it must be a **single** 209 | expression that does **not** start with `...`, and it cannot be a parenthesized 210 | argument list either. 211 | 212 | The pipeline is therefore equivalent to:\ 213 | `do` `{`\ 214 |   `const `\ 215 |     `[` #₀[0] `,` … `,` #₀[max topic index(𝐸₀)] `,` `...` #₀[r] `]` `=`\ 216 |       `[`\ 217 |         𝐸₀[0] `,`\ 218 |         𝐸₀[1] `,`\ 219 |         … `,`\ 220 |         𝐸₀[width(𝐸₀)−2]\ 221 |         𝐸₀[width(𝐸₀)−1]\ 222 |     `]` `,`\ 223 |     `[` #₁[0] `,` … `,` #₁[max topic index(𝐸₁)] `,` `... ` #₁[r] `]` `=`\ 224 |       `[`\ 225 |           sub(𝐸₁[0], #₀[0], #₀[1], #₀[2], #₀[r]) `,`\ 226 |           sub(𝐸₁[1], #₀[0], #₀[1], #₀[2], #₀[r]) `,`\ 227 |           …\ 228 |           sub(𝐸₁[width(𝐸₁)−2], #₀[0], #₀[1], #₀[2], #₀[r]) `,`\ 229 |           sub(𝐸₁[width(𝐸₁)−1], #₀[0], #₀[1], #₀[2], #₀[r]) `,`\ 230 |       `]` `,`\ 231 |     `[` #₂[0] `,` … `,` #₂[max topic index(𝐸₂)] `,` `... ` #₂[r] `]` `=`\ 232 |       `[`\ 233 |           sub(𝐸₂[0], #₀[0], #₀[1], #₀[2], #₀[r]) `,`\ 234 |           sub(𝐸₂[1], #₀[0], #₀[1], #₀[2], #₀[r]) `,`\ 235 |           …\ 236 |           sub(𝐸₂[width(𝐸₂)−2], #₀[0], #₀[1], #₀[2], #₀[r]) `,`\ 237 |           sub(𝐸₂[width(𝐸₂)−1], #₀[0], #₀[1], #₀[2], #₀[r]) `,`\ 238 |       `]` `,`\ 239 |     … `,`\ 240 |     `[` #ᵤ₋₂[0] `,` #ᵤ₋₂[1] `,` … `,` `... ` (#ᵤ₋₂)ₛ `]` `=`\ 241 |       `[`\ 242 |           sub(𝐸ᵤ₋₂[0], #₀[0], #₀[1], #₀[2], #₀[r]) `,`\ 243 |           sub(𝐸ᵤ₋₂[1], #₀[0], #₀[1], #₀[2], #₀[r]) `,`\ 244 |           … `,`\ 245 |           sub(𝐸ᵤ₋₂[width(𝐸ᵤ₋₂)−2], #₀[0], #₀[1], #₀[2], #₀[r]) `,`\ 246 |           sub(𝐸ᵤ₋₂[width(𝐸ᵤ₋₂)−1], #₀[0], #₀[1], #₀[2], #₀[r]) `,`\ 247 |       `]` `;`\ 248 |   sub(𝐸ᵤ₋₁, #ᵤ₋₂[0], #ᵤ₋₂[1], …, #ᵤ₋₂[width(𝐸ᵤ₋₂)−1]) `;`\ 249 | `}`. 250 | 251 | *** 252 | 253 | [TODO: Define width(𝐸) and max topic index(𝐸).] 254 | 255 | *** 256 | 257 | * If 𝑃 is a [bare function call][] – then sub(𝑃, #[0], #[1], …, #[m]) is 258 | 𝑃 `(` [TODO] `)`. 259 | * If 𝑃 is a [bare awaited function call][] – then sub(𝑃, #[0], #[1], …, #[m]) 260 | is `await` 𝑃 `(` [TODO] `)`. 261 | * If 𝑃 is a [bare constructor call][] – then sub(𝑃, #[0], #[1], …, #[m]) is 262 | `new` 𝑃 `(` [TODO] `)`. 263 | * [TODO] If 𝑃 is in [topic style][] – then sub(𝑃, #[0], #[1], #[2], #ₛ) is 𝑃 but in which 264 | all unshadowed instances of the primary topic reference `#` are replaced by 265 | #[0], unshadowed instances of the secondary topic reference `##` are replaced 266 | by #[1], unshadowed instances of the tertiary topic reference `###` are 267 | replaced by #[2], and unshadowed instances of the rest topic reference `...` 268 | are replaced by `...` #ₛ. 269 | 270 | ["data-to-ink" visual ratio]: https://www.darkhorseanalytics.com/blog/data-looks-better-naked 271 | ["don’t break my code"]: ./goals.md#dont-break-my-code 272 | ["don’t make me overthink"]: ./goals.md#dont-make-me-overthink 273 | ["don’t shoot me in the foot"]: ./goals.md#dont-shoot-me-in-the-foot 274 | ["make my code easier to read"]: ./goals.md#make-my-code-easier-to-read 275 | [`??:`]: https://github.com/tc39/proposal-nullish-coalescing/pull/23 276 | [`do` expression]: ./relations.md#do-expressions 277 | [`do` expressions]: ./relations.md#do-expressions 278 | [`for` iteration statements]: https://tc39.github.io/ecma262/#sec-iteration-statements 279 | [`in` relational operator]: https://tc39.github.io/ecma262/#sec-relational-operators 280 | [`match` expressions]: ./relations.md#pattern-matching 281 | [`new.target`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new.target 282 | [Additional Feature BA]: ./additional-feature-ba.md 283 | [Additional Feature BC]: ./additional-feature-bc.md 284 | [Additional Feature BP]: ./additional-feature-bp.md 285 | [Additional Feature NP]: ./additional-feature-np.md 286 | [Additional Feature PF]: ./additional-feature-pf.md 287 | [Additional Feature TS]: ./additional-feature-ts.md 288 | [additional features]: ./readme.md#additional-features 289 | [annevk]: https://github.com/annevk 290 | [antecedent]: https://en.wikipedia.org/wiki/Antecedent_(grammar) 291 | [arbitrary associativity]: ./goals.md#arbitrary-associativity 292 | [ASI]: https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion 293 | [associative property]: https://en.wikipedia.org/wiki/Associative_property 294 | [async pipeline functions]: ./additional-feature-pf.md 295 | [Babel plugin]: https://github.com/valtech-nyc/babel/ 296 | [Babel update summary]: https://github.com/babel/proposals/issues/29#issuecomment-372828328 297 | [background]: ./readme.md 298 | [backward compatibility]: ./goals.md#backward-compatibility 299 | [bare awaited function call]: ./core-syntax.md#bare-style 300 | [bare constructor call]: ./core-syntax.md#bare-style 301 | [bare function call]: ./core-syntax.md#bare-style 302 | [bare style]: ./core-syntax.md#bare-style 303 | [binding]: https://en.wikipedia.org/wiki/Binding_(linguistics) 304 | [block parameters]: ./relations.md#block-parameters 305 | [Clojure compact function]: https://clojure.org/reference/reader#_dispatch 306 | [Clojure pipe]: https://clojuredocs.org/clojure.core/as-%3E 307 | [completion records]: https://timothygu.me/es-howto/#completion-records-and-shorthands 308 | [concatenative programming]: https://en.wikipedia.org/wiki/Concatenative_programming_language 309 | [conceptual generality]: ./goals.md#conceptual-generality 310 | [Core Proposal]: ./readme.md 311 | [core-real-examples.md]: ./core-real-examples.md 312 | [currying]: https://en.wikipedia.org/wiki/Currying 313 | [cyclomatic complexity]: https://en.wikipedia.org/wiki/Cyclomatic_complexity#Applications 314 | [cyclomatic simplicity]: ./goals.md#cyclomatic-simplicity 315 | [dataflow programming]: https://en.wikipedia.org/wiki/Dataflow_programming 316 | [distinguishable punctuators]: ./goals.md#distinguishable-punctuators 317 | [don’t break my code]: ./goals.md#dont-break-my-code 318 | [DSLs]: https://en.wikipedia.org/wiki/Domain-specific_language 319 | [early error rule]: ./goals.md#static-analyzability 320 | [early error rules]: ./goals.md#static-analyzability 321 | [early error]: ./goals.md#static-analyzability 322 | [early errors]: ./goals.md#static-analyzability 323 | [ECMAScript _Identifier Name_]: https://tc39.github.io/ecma262/#prod-IdentifierName 324 | [ECMAScript _Identifier Reference_]: https://tc39.github.io/ecma262/#prod-IdentifierReference 325 | [ECMAScript _Member Expression_]: https://tc39.github.io/ecma262/#prod-MemberExpression 326 | [ECMAScript § The Syntactic Grammar]: https://tc39.github.io/ecma262/#sec-syntactic-grammar 327 | [ECMAScript `new` operator, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-new-operator-runtime-semantics-evaluation 328 | [ECMAScript arrow functions, § SS: Contains]: https://tc39.github.io/ecma262/#sec-arrow-function-definitions-static-semantics-contains 329 | [ECMAScript Assignment-level Expressions]: https://tc39.github.io/ecma262/#sec-assignment-operators 330 | [ECMAScript block parameters]: https://github.com/samuelgoto/proposal-block-params 331 | [ECMAScript Blocks, § RS: Block Declaration Instantiation]: https://tc39.github.io/ecma262/#sec-blockdeclarationinstantiation 332 | [ECMAScript Blocks, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-block-runtime-semantics-evaluation 333 | [ECMAScript Declarative Environment Records]: https://tc39.github.io/ecma262/#sec-declarative-environment-records 334 | [ECMAScript function binding]: https://github.com/zenparsing/es-function-bind 335 | [ECMAScript Function Calls, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-function-calls-runtime-semantics-evaluation 336 | [ECMAScript Function Environment Records]: https://tc39.github.io/ecma262/#sec-function-environment-records 337 | [ECMAScript Functions and Classes § Generator Function Definitions]: https://tc39.github.io/ecma262/#sec-generator-function-definitions 338 | [ECMAScript Get This Environment]: https://tc39.github.io/ecma262/#sec-getthisenvironment 339 | [ECMAScript headless-arrow proposal]: https://bterlson.github.io/headless-arrows/ 340 | [ECMAScript Lexical Environments]: https://tc39.github.io/ecma262/#sec-lexical-environments 341 | [ECMAScript Lexical Grammar]: https://tc39.github.io/ecma262/#sec-ecmascript-language-lexical-grammar 342 | [ECMAScript LHS expressions]: https://tc39.github.io/ecma262/#sec-left-hand-side-expressions 343 | [ECMAScript Lists and Records]: https://tc39.github.io/ecma262/#sec-list-and-record-specification-type 344 | [ECMAScript Notational Conventions, § Algorithm Conventions]: https://tc39.github.io/ecma262/#sec-algorithm-conventions-abstract-operations 345 | [ECMAScript Notational Conventions, § Grammars]: https://tc39.github.io/ecma262/#sec-syntactic-and-lexical-grammars 346 | [ECMAScript Notational Conventions, § Lexical Grammar]: https://tc39.github.io/ecma262/#sec-lexical-and-regexp-grammars 347 | [ECMAScript Notational Conventions, § Runtime Semantics]: https://tc39.github.io/ecma262/#sec-runtime-semantics 348 | [ECMAScript optional `catch` binding]: https://github.com/tc39/proposal-optional-catch-binding 349 | [ECMAScript partial application]: https://github.com/tc39/proposal-partial-application 350 | [ECMAScript pattern matching]: https://github.com/tc39/proposal-pattern-matching 351 | [ECMAScript Primary Expressions]: https://tc39.github.io/ecma262/#prod-PrimaryExpression 352 | [ECMAScript Property Accessors, § RS: Evaluation]: https://tc39.github.io/ecma262/#sec-property-accessors-runtime-semantics-evaluation 353 | [ECMAScript Punctuators]: https://tc39.github.io/ecma262/#sec-punctuators 354 | [ECMAScript static semantic rules]: https://tc39.github.io/ecma262/#sec-static-semantic-rules 355 | [Elixir pipe]: https://hexdocs.pm/elixir/Kernel.html#%7C%3E/2 356 | [Elm pipe]: http://elm-lang.org/docs/syntax#infix-operators 357 | [essential complexity]: https://en.wikipedia.org/wiki/Essential_complexity 358 | [expressions and operators (MDN)]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators 359 | [expressive versatility]: ./goals.md#expressive-versatility 360 | [F# pipe]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/functions/index#function-composition-and-pipelining 361 | [first pipe-operator proposal]: https://github.com/tc39/proposal-pipeline-operator/blob/37119110d40226476f7af302a778bc981f606cee/README.md 362 | [footguns]: https://en.wiktionary.org/wiki/footgun 363 | [formal BA]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-ba 364 | [formal BC]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-bc 365 | [formal BP]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-bp 366 | [formal CP]: https://jschoi.org/18/es-smart-pipelines/spec#introduction 367 | [formal NP]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-np 368 | [formal PF]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-pf 369 | [formal pipeline specification]: https://jschoi.org/18/es-smart-pipelines/spec 370 | [formal TS]: https://jschoi.org/18/es-smart-pipelines/spec#sec-additional-feature-ts 371 | [forward compatibility]: ./goals.md#forward-compatibility 372 | [forward compatible]: ./goals.md#forward-compatibility 373 | [function bind operator `::`]: ./relations.md#function-bind-operator 374 | [function binding]: ./relations.md#function-binding 375 | [function composition]: ./relations.md#function-composition 376 | [functional programming]: https://en.wikipedia.org/wiki/Functional_programming 377 | [gajus functional composition]: https://github.com/gajus/babel-plugin-transform-function-composition 378 | [garden-path syntax]: https://en.wikipedia.org/wiki/Garden_path_sentence 379 | [GitHub issue tracker]: https://github.com/tc39/proposal-pipeline-operator/issues 380 | [goals]: ./goals.md 381 | [Hack pipe]: https://docs.hhvm.com/hack/operators/pipe-operator 382 | [Huffman coding]: https://en.wikipedia.org/wiki/Huffman_coding 383 | [human writability]: ./goals.md#human-writability 384 | [i-am-tom functional composition]: https://github.com/fantasyland/ECMAScript-proposals/issues/1#issuecomment-306243513 385 | [identity function]: https://en.wikipedia.org/wiki/Identity_function 386 | [IIFEs]: https://en.wikipedia.org/wiki/Immediately-invoked_function_expression 387 | [immutable objects]: https://en.wikipedia.org/wiki/Immutable_object 388 | [incidental complexity]: https://en.wikipedia.org/wiki/Incidental_complexity 389 | [intro]: readme.md 390 | [isiahmeadows functional composition]: https://github.com/isiahmeadows/function-composition-proposal 391 | [jashkenas]: https://github.com/jashkenas 392 | [jQuery + CP]: ./core-real-examples.md#jquery 393 | [jQuery]: https://jquery.com/ 394 | [jquery/src/core/access.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/access.js 395 | [jquery/src/core/init.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/init.js 396 | [jquery/src/core/parseHTML.js]: https://github.com/jquery/jquery/blob/2.2-stable/src/core/parseHTML.js 397 | [JS Foundation]: https://js.foundation/ 398 | [Julia pipe]: https://docs.julialang.org/en/stable/stdlib/base/#Base.:|> 399 | [lexical topic]: https://jschoi.org/18/es-smart-pipelines/spec#sec-lexical-topics 400 | [lexically hygienic]: https://en.wikipedia.org/wiki/Hygienic_macro 401 | [littledan invitation]: https://github.com/tc39/proposal-pipeline-operator/issues/89#issuecomment-363853394 402 | [littledan]: https://github.com/littledan 403 | [LiveScript pipe]: http://livescript.net/#operators-piping 404 | [Lodash + CP + BP + PF]: ./additional-feature-pf.md#lodash-core-proposal--additional-feature-bppf 405 | [Lodash + CP + BP + PP + PF + NP]: ./additional-feature-np.md#lodash-core-proposal--additional-features-bppppfmt 406 | [Lodash + CP]: ./core-real-examples.md#lodash 407 | [Lodash]: https://lodash.com/ 408 | [mAAdhaTTah]: https://github.com/mAAdhaTTah/ 409 | [make my code easier to read]: ./goals.md#make-my-code-easier-to-read 410 | [MDN operator precedence]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence 411 | [MDN operator precedence]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table 412 | [method-extraction inline caching]: https://github.com/tc39/proposal-bind-operator/issues/46 413 | [mindeavor]: https://github.com/gilbert 414 | [mode errors]: https://en.wikipedia.org/wiki/Mode_(computer_interface)#Mode_errors 415 | [motivation]: ./readme.md 416 | [Node-stream piping]: https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options 417 | [Node.js `util.promisify`]: https://nodejs.org/api/util.html#util_util_promisify_original 418 | [nomenclature]: ./nomenclature.md 419 | [novice learnability]: ./goals.md#novice-learnability 420 | [nullish coalescing proposal]: https://github.com/tc39/proposal-nullish-coalescing/ 421 | [object initializers’ Computed Property Contains rule]: https://tc39.github.io/ecma262/#sec-object-initializer-static-semantics-computedpropertycontains 422 | [OCaml pipe]: http://blog.shaynefletcher.org/2013/12/pipelining-with-operator-in-ocaml.html 423 | [operator precedence]: ./core-syntax.md#operator-precedence-and-associativity 424 | [opt-in behavior]: ./goals.md#opt-in-behavior 425 | [optional `catch` binding]: ./relations.md#optional-catch-binding 426 | [optional-chaining syntax proposal]: https://github.com/tc39/proposal-optional-chaining 427 | [other browsers’ console variables]: https://www.andismith.com/blogs/2011/11/25-dev-tool-secrets/ 428 | [other ECMAScript proposals]: ./relations.md#other-ecmascript-proposals 429 | [other goals]: ./goals.md#other-goals 430 | [pattern matching]: ./relations.md#pattern-matching 431 | [partial function application]: ./goals.md#partial-function-application 432 | [PEP 20]: https://www.python.org/dev/peps/pep-0020/ 433 | [Perl 6 pipe]: https://docs.perl6.org/language/operators#infix_==> 434 | [Perl 6 topicization]: https://www.perl.com/pub/2002/10/30/topic.html/ 435 | [Perl 6’s given block]: https://docs.perl6.org/language/control#given 436 | [pipeline functions]: ./additional-feature-pf.md 437 | [Pipeline Proposal 1]: https://github.com/tc39/proposal-pipeline-operator/wiki#proposal-1-f-sharp-only 438 | [Pipeline Proposal 4]: https://github.com/tc39/proposal-pipeline-operator/wiki#proposal-4-smart-mix 439 | [pipeline syntax]: ./core-syntax.md 440 | [pipelines]: ./readme.md 441 | [previous pipeline-placeholder discussions]: https://github.com/tc39/proposal-pipeline-operator/issues?q=placeholder 442 | [primary topic]: ./readme.md 443 | [private class fields]: https://github.com/tc39/proposal-class-fields/ 444 | [pure functions]: https://en.wikipedia.org/wiki/Pure_function 445 | [R pipe]: https://cran.r-project.org/web/packages/magrittr/vignettes/magrittr.html 446 | [Ramda + CP + BP + PF + NP]: ./additional-feature-np.md#ramda-core-proposal--additional-features-bppfmt 447 | [Ramda + CP + BP + PF]: ./additional-feature-pf.md#ramda-core-proposal--additional-feature-bppf 448 | [Ramda wiki cookbook]: https://github.com/ramda/ramda/wiki/Cookbook 449 | [Ramda]: http://ramdajs.com/ 450 | [relations to other work]: ./relations.md 451 | [REPLs]: https://en.wikipedia.org/wiki/Read–eval–print_loop 452 | [rest topic]: ./additional-feature-np.md 453 | [reverse Polish notation]: https://en.wikipedia.org/wiki/Reverse_Polish_notation 454 | [robust method extraction]: https://github.com/tc39/proposal-pipeline-operator/issues/110#issuecomment-374367888 455 | [Ron Buckton]: https://github.com/rbuckton 456 | [secondary topic]: ./additional-feature-np.md 457 | [semantic clarity]: ./goals.md#semantic-clarity 458 | [simonstaton functional composition]: https://github.com/simonstaton/Function.prototype.compose-TC39-Proposal 459 | [simple scoping]: ./goals.md#simple-scoping 460 | [sindresorhus]: https://github.com/sindresorhus 461 | [smart step syntax]: ./core-syntax.md 462 | [smart pipelines]: ./readme.md#smart-pipelines 463 | [Standard Style]: https://standardjs.com/ 464 | [static analyzability]: ./goals.md#static-analyzability 465 | [statically analyzable]: ./goals.md#static-analyzability 466 | [statically detectable early errors]: ./goals.md#static-analyzability 467 | [syntactic locality]: ./goals.md#syntactic-locality 468 | [tacit programming]: https://en.wikipedia.org/wiki/Tacit_programming 469 | [TC39 60th meeting, pipelines]: https://tc39.github.io/tc39-notes/2017-09_sep-26.html#11iia-pipeline-operator 470 | [TC39 process]: https://tc39.github.io/process-document/ 471 | [tc39/proposal-decorators#30]: tc39/proposal-decorators#30 472 | [tc39/proposal-decorators#42]: tc39/proposal-decorators#42 473 | [tc39/proposal-decorators#60]: tc39/proposal-decorators#60 474 | [Tennent correspondence principle]: http://gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html 475 | [term rewriting]: ./term-rewriting.md 476 | [terse composition]: ./goals.md#terse-composition 477 | [terse function application]: ./goals.md#terse-function-application 478 | [terse function calls]: ./goals.md#terse-function-calls 479 | [terse method extraction]: ./goals.md#terse-method-extraction 480 | [terse parentheses]: ./goals.md#terse-parentheses 481 | [terse partial application]: ./goals.md#terse-partial-application 482 | [terse variables]: ./goals.md#terse-variables 483 | [tertiary topic]: ./additional-feature-np.md 484 | [TheNavigateur functional composition]: https://github.com/TheNavigateur/proposal-pipeline-operator-for-function-composition 485 | [topic and comment]: https://en.wikipedia.org/wiki/Topic_and_comment 486 | [topic references in other programming languages]: ./relations.md#topic-references-in-other-programming-languages 487 | [topic style]: ./core-syntax.md#topic-style 488 | [topic variables in other languages]: https://rosettacode.org/wiki/Topic_variable 489 | [topic-token bikeshedding]: https://github.com/tc39/proposal-pipeline-operator/issues/91 490 | [Underscore.js + CP + BP + PP]: ./additional-feature-pp.md#underscorejs-core-proposal--additional-feature-bppp 491 | [Underscore.js + CP]: ./core-real-examples.md#underscorejs 492 | [Underscore.js]: http://underscorejs.org 493 | [Unix pipe]: https://en.wikipedia.org/wiki/Pipeline_(Unix 494 | [untangled flow]: ./goals.md#untangled-flow 495 | [Visual Basic’s `select` statement]: https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/select-case-statement 496 | [WebKit console variables]: https://webkit.org/blog/829/web-inspector-updates/ 497 | [WHATWG Fetch + CP]: ./core-real-examples.md#whatwg-fetch-standard 498 | [WHATWG Fetch Standard]: https://fetch.spec.whatwg.org/ 499 | [WHATWG Streams + CP + BP + PF + NP]: ./additional-feature-np.md#whatwg-streams-standard-core-proposal--additional-features-bppfmt 500 | [WHATWG Streams + CP + BP + PF]: ./additional-feature-pf.md#whatwg-streams-standard-core-proposal--additional-feature-bppf 501 | [WHATWG Streams Standard]: https://stream.spec.whatwg.org/ 502 | [WHATWG-stream piping]: https://streams.spec.whatwg.org/#pipe-chains 503 | [Wikipedia: term rewriting]: https://en.wikipedia.org/wiki/Term_rewriting 504 | [zero runtime cost]: ./goals.md#zero-runtime-cost 505 | --------------------------------------------------------------------------------