【TC39 Proposals】do expressions


注意書き

2019 年 10 月 9 日に開催の #tc39_study 用に作成した資料です。
執筆時点で TC39 の Proposals に上がっている機能を紹介します。
将来的に JavaScript(ECMAScript)に取り入れられるかもしれませんし、取り入れられないかもしれませんし、紹介内容から仕様が大きく変更になるかもしれません。
TC39 の承認プロセスについては、https://tc39.es/process-document/ をご覧ください。


do-expressions

ブロックの末尾の式(completion value)を値として返せるようにします。

例えば、変数 x を初期化するために一時変数 tmp を使うとします。
tmpx のためにしか使わないので、適切にブロックで囲ってあげたくなります。
現時点だと以下のように即時関数を用いるのが簡単な方法でしょう。

const x = (() => {
  let tmp = f();
  return tmp * tmp + 1
})();

これをより簡潔にするのが do-expressions です。
doブロックの最後の式が値として返るので、以下のように書くことができます。

const x = do {
  let tmp = f();
  tmp * tmp + 1
};

if文との組み合わせ

doブロックの末尾にif文を書くことで、if文のブロックの末尾の式がdoブロックの戻り値として返ります。

let x = do {
  if (foo()) { f() }
  else if (bar()) { g() }
  else { h() }
};

JSXでの利用

JSX内で以下のような書き方ができるようになります。

return (
  <nav>
    <Home />
    {
      do {
        if (loggedIn) {
          <LogoutButton />
        } else {
          <LoginButton />
        }
      }
    }
  </nav>
)

懸念点

do-while と組み合わせた場合の文法上の曖昧性を回避する必要があります。

do do f(); while (x);

その他の議論点

issueに上がってる論点をいくつか紹介します。


非同期まわり

do async {} (or async do {})とか

Generatorまわり

do * {} とか

例外まわり

こんな感じで動いてほしい。

const foo = () => do { throw new Error('foo'); };
const bar = () => 3;
const res = do {
  try { foo(); } catch (e) { bar(); }
}
console.log(res); // 3;

doいらなくね?

代替案

  • {>let x = 100; x * x}
  • let x = {| /* blah */ |}
  • non ASCIIな記号を使う(« » 「 」 〈〉 《 》 【 】 〔 〕 ⦗ ⦘)


doブロック内でのreturnとか

doブロック内で return した場合に、doブロックの値になるべきか関数の戻り値になるべきか?

あと var continue break をどうするか。

https://github.com/tc39/proposal-do-expressions/issues/30
https://github.com/tc39/tc39-notes/blob/master/meetings/2018-07/july-24.md#update-on-do-expressions


今すぐ使いたい人へ

babelのpluginが使えます。


所感

気持ちはわかったが議論を見る限り標準化はなかなか難しそう。
条件分岐に関してはPattern Matchingでもできるので、もう少し複雑なケースでの住み分けか。


参考情報