😊

【bugs.ruby Advent Calender】case ~ when で rescue 句も含めるようにする提案【9日目】

2024/12/08に公開

bugs.ruby Advent Calender 9日目の記事です。

これはなに

今年1年間通してみてきた bugs.ruby のチケットの中から気になったものを1つずつ取り上げていく Advent Calender です。
取り上げるチケットは基本的にこのブログで取り上げたものになります。
記事のまとめは ここを参照 してください。

[Feature #20160] rescue keyword for case expressions

case ~ when で発生した例外を次のような rescue 句で受け取ることができようにする提案です。

case (parsed = parse(input))
when Integer
  handle_int(parsed)
when Float
  handle_float(parsed)
else
  # when に該当しなかった場合
rescue ParseError
  # ParseError が発生した場合
rescue ArgumentError
  # ArgumentError が発生した場合
ensure
  # ... すべてのケースから呼び出される
end

要は case ~ whenbegin ~ rescue ~ end を1つの式で表現できるようにする提案ですね。
現状だと次のように記述する必要があります。

begin
  case (parsed = parse(input))
  when Integer
    handle_int(parsed)
  when Float
    handle_float(parsed)
  else
    # ...
  end
rescue ParseError
  # ...
end

この提案自体は『処理すべき例外の発生源について混乱する可能性がある』『(コメントに提示されていた)以下のコードの方が直感的でわかりやすい』ということで Reject されていますねー。
結局は例外の処理がどこにかかっているのかが case なのかどの when なのかわからない、みたいな感じですかねー。
なので次のように『例外が発生する可能性がある箇所ごと』に rescue するほうがわかりやすいとのこと。

# parse で例外が発生しうるのであればこっちで rescue する
begin
  parsed = parse(input)
rescue ParseError
  # ...
end

case parsed
when Integer
  handle_int(parsed)
when Float
  handle_float(parsed)
end

ちなみにコメントでは以下のようなパターンマッチを利用するコードも提示されていますね。

def parse(input)
  # parsing logic
rescue StandardError => e
  [:error, e]
end


case parse(input)
in Integer => parsed_int
  handle_int(parsed_int)
in Float => parsed_float
  handle_float(parsed_float)
in :error, ParseError => error
  # ParseError の場合
in :error, ArgumentError => error
  # ArgumentError の場合
else
  # どれにも該当しない場合
end

こういうのは好き

関連

GitHubで編集を提案

Discussion