tc39/proposal-pipeline-operator の 過去と現状
pipeline-operator の ドラフトを 振り返る
tc39/proposal-pipeline-operator の
let result = exclaim(capitalize(doubleSay("hello")));
result //=> "Hello, hello!"
let result = "hello"
|> doubleSay
|> capitalize
|> exclaimF# や Elixir などに触れているひとは,
c(b(a)) のような関数呼び出しがネストしたケースで,a |> b |> c と,
この仕様としては,, より強く,
長い期間 Stage-1 にとどまり続けた理由
pipeline-operator は 2017年に Stage-1 になってから 三年間 Stage-2 に上がることはありませんでした.
F#-style pipeline における ASI との競合
非同期を
function doubleSay (str) {
return str + ", " + str;
}
async function capitalize (str) {
let response = await
capitalizeOnTheServer(str);
return response.getCapitalized();
}
function exclaim (str) {
return str + '!';
}
let result = "hello"
|> doubleSay
|> capitalize
|> exclaim;
// result => "[Object Promise]"普通に pipeline を
let result = await ("hello"
|> doubleSay
|> capitalize)
|> exclaimこの様になってしまいます.
let result = "hello"
|> doubleSay
|> await capitalize
|> exclaim;ここで新たに生じた問題が,
let result = "hello"
|> doubleSay
|> (await capitalize)
|> exclaim;その問題を|> await という構文が提案されました.
let result = "hello"
|> doubleSay
|> await
|> capitalize
|> exclaim;|> await という構文を
let promise = "hello"
|> doubleSay
|> await
exclaim(capitalize(promise))既存の async / await では,
await
asyncFn()と記述することができます.
let promise = "hello"
|> doubleSay
|> await;
exclaim(capitalize(promise))let promise = "hello"
|> doubleSay
|> await
exclaim(capitalize(promise));上記のどちらと判断すればよいかわからず,await |> や |> await |> なども|> await で終わる pipeline を許さないための構文) 結果的に,
await の問題を解決するために, 過去に drop された hack style の 復活が提案される
pipeline operator 下で,"split-mix pipes" と"smart-mix pipes" (proposal-smart-pipeline) です.
2つに共通している点は,Placeholder をawait, yield を
split-mix は |> と |>> (厳密には,smart-mix は 関数をPlaceholder によってどこに適用するか,
- split-mix
// Basic Usage
x |>> f //--> f(x)
x |> f(^) //--> f(x)
x |>> f(y) //--> f(y)(x)
x |> f(y)(^) //--> Syntax Error
// 2+ Arity Usage
x |> f(^, 10) //--> f(x,10)
// Async solution (does not require special casing)
x |> await f(^) //--> await f(x)
x |> await f(^) |> g //--> g(await f(x))
// Other expressions
f(x) |> ^.data //--> f(x).data
f(x) |> ^[^.length-1] //--> let temp=f(x), temp[temp.length-1]
f(x) |> { result: ^ } //--> { result: f(x) }split-mix は,
- smart-mix
// Basic Usage
x |> f //--> f(x)
x |> f(^) //--> f(x)
// 2+ Arity Usage
x |> f(y) //--> Syntax Error
x |> f(y, ^) //--> f(y, x)
x |> f(^, y) //--> f(x, y)
x |> f(y)(^) //--> f(y)(x)
// Async Solution (Note this would not require special casing)
x |> await f(^) //--> await f(x)
x |> await f(^) |> g //--> g(await f(x))
// Arbitrary Expressions
f(x) |> ^.data //--> f(x).data
f(x) |> ^[^.length-1] //--> let temp=f(x), temp[temp.length-1]
f(x) |> { result: ^ } //--> { result: f(x) }pipeline-operator を Stage-2 に上げるために再挑戦
2018年3月に,
2018年7月には,
これにより,
@codehag 氏(Mozilla SpiderMonkey チーム)は,
ここから三年間に渡り,
2021年 pipeline-operator が Stage-2 に上がるにあたって起きたこと
State of JS 2020 にて pipeline operator が話題に上がる
2021年1月に State of JS 2020 にて,
これがきっかけの1つとなったかどうかはわかりませんが,

2021年3月に,
また,
この,
再度 Stage-2 に向けて
再度,
8月31日の正式な委員会で,
それに対して,
- 他の proposal である bind-operator と将来的に衝突してしまうのではないか
- @codehag 氏 (Mozilla SpiderMonkey) はいずれにしても pipeline には若干後ろ向き,
ただし Stage-2 を ブロックするほどではない
という指摘がなされました.
これ以外に,
備考として,
仕様を 固めるために Placeholder の トークンを 決める
2021年10月末から議論されているトピックとして,
以前は ? が提案されていました,
? が抱えている問題
? を
value |> fn(10, ?)これを
value |> fn(10, ? ? cond1(?) : defaultValue)value |> fn(10, ? ?? defaultValue)また,
value |> fn(10, ? ?? ? ? ? : ?)
~ ~~ ~ ~ ~ ~ ~
| |_|_|_|_|_|_______ nullish coalescing operator
| | | | | |
|____._|_._|_.____ placeholder of pipeline
| |
|___.___ conditional ternary operator% が抱えている問題
% も ? に近い課題を% 単体で オペレーターとしてすでにあるので
value |> fn(20 % %)のようなコードが発生してしまいます,% operator か どうか判断するのは非常に困難です.# でも同様に,
これらのことから,
## や (), $_, @, ^ など 様々なアイデアが github 上 の issue で 議論されています.$, _ 及びそれらの組み合わせは,
Stage-3 の条件としては,
現状の Hack-style pipeline の仕様
最後に,% になれば以下のようになります
value |> foo(%)for unary function calls,value |> foo(1, %)for n-ary function calls,value |> %.foo()for method calls,value |> % + 1for arithmetic,value |> [%, 0]for array literals,value |> {foo: %}for object literals,value |> \`${%}\``for template literals,value |> new Foo(%)for constructing objects,value |> await %for awaiting promises,value |> (yield %)for yielding generator values,value |> import(%)for calling function-like keywords,
おわりに
この記事では,
東京Node学園祭'2018 にて,
pipeline-operator や partial-function-application, pattern-matching, bind-operator などの仕様が JavaScript に実装されたときには,