--- [article] uuid = "87455008-fe5b-49bf-af5a-b875264f8326" title = "【Ruby】 then キーワードと case in" description = "Ruby 3.0 で追加される case in 構文と、then キーワードについて。" tags = [ "ruby", "ruby3", ] [[article.revisions]] date = "2021-10-02" remark = "Qiita から移植" ---
この記事は Qiita から移植してきたものです。 元 URL: https://qiita.com/nsfisis/items/787a8cf888a304497223
TL; DR

case - in によるパターンマッチング構文でも、case - when と同じように then が使える (場合によっては使う必要がある)。

then とは

使われることは稀だが、Ruby では then がキーワードになっている。次のように使う:

このキーワードが現れうる場所はいくつかあり、ifunlessrescuecase 構文がそれに当たる。 上記のように、何か条件を書いた後 then を置き、式がそこで終了していることを示すマーカーとして機能する。

なぜ普段は書かなくてもよいのか

普通 Ruby のコードで then を書くことはない。なぜか。次のコードを実行してみるとわかる。

次のような構文エラーが出力される。

二つ目のメッセージは無視して一つ目を読むと、then; か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。

ポイントは改行が then (や ;) の代わりとなることである。true の後に改行を入れてみる。

無事 Hello, World! と出力されるようになった。

なぜ then; や改行が必要か

なぜ then; や改行 (以下 「then 等」) が必要なのだろうか。次の例を見てほしい:

then; も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。 この例は二通りに解釈できる。

then 等はこの曖昧性を排除するためにあり、条件式は if から then 等までの間にある、ということを明確にする。 C系の if 後に来る (/) や、Python の :、Rust/Go/Swift などの { も同じ役割を持つ。

Ruby の場合、プログラマーが書きやすいよう改行でもって then が代用できるので、ほとんどの場合 then は必要ない。

case - in における then

ようやく本題にたどり着いた。来る Ruby 3.0 では casein キーワードを使ったパターンマッチングの構文が入る予定である。この構文でもパターン部との区切りとして then 等が必要になる。 (現在の) Ruby には formal な形式での文法仕様は存在しないので、yacc の定義ファイルを参照した (yacc の説明は省略)。

https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986

command_start = FALSE; $1 = p->ctxt; p->ctxt.in_kwarg = 1; $$ = push_pvtbl(p); } { $$ = push_pktbl(p); } p_top_expr then { pop_pktbl(p, $3); pop_pvtbl(p, $2); p->ctxt.in_kwarg = $1.in_kwarg; } compstmt p_cases { /*%%%*/ $$ = NEW_IN($4, $7, $8, &@$); /*% %*/ /*% ripper: in!($4, $7, escape_Qundef($8)) %*/ } ; ]]>

簡略版:

ここで、keyword_in は文字通り inp_top_expr はいわゆるパターン、thenthen キーワードのことではなく、この記事で then 等と呼んでいるもの、つまり then キーワード、;、改行のいずれかである。

これにより、case - when による従来の構文と同じように、then 等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる:

ところで、p_top_expr には if による guard clause が書けるので、その場合は if - then と似たような見た目になる。

まとめ