tc39/proposal-pipeline-operator の 過去と現状
pipeline-operator の ドラフトを 振り返る
tc39/proposal-pipeline-operator の
let result = exclaim(capitalize(doubleSay("hello")));
result //=> "Hello, hello!"
let result = "hello"
|> doubleSay
|> capitalize
|> exclaim
F# や 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 |> % + 1
for 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 に実装されたときには,