👌

【bugs.ruby Advent Calender】case ~ in ~ end で ... を渡せるようにする提案【4日目】

2024/12/04に公開

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

これはなに

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

[Feature #20318] Pattern matching case ... in support for triple-dot arguments

case ~ in ~ end... を渡せるようにする提案です。
... は転送引数で『なんでも受け入れる引数』みたいな構文ですね。

def hoge(...)
  # このメソッドに渡された引数をすべて他の引数に転送できる
  pp(...)
end

hoge(1, 2, a: 3)
__END__
output:
1
2
{:a=>3}

これとパターンマッチを組み合わせることによって『引数の状態によって処理を切り分ける』ような使い方を想定しています。

def foo(...)
  case ...
  in args: [name]
    puts name
  in args: [first_name, last_name]
    puts "Hi there #{first_name} #{last_name}"
  in kwargs: {greeting:}
    puts "Hello #{greeting}"
  else
    puts "No match: #{args}"
  end
end

foo "Hi"                # => Hi
foo "Brad", "Gessler"   # => Hi there Brad Gessler
foo greeting: "Brad"    # => Hello Brad

提案では args が位置引数を参照し kwargs がキーワード引数を参照する、みたいなイメージですね。
既存のコードでは以下と同じような形になります。

def foo(*args, **kwargs, &block)
  case { args:, kwargs:, block: }
  in args: [name]
    # ...
  end
end

他にもコメントで、以下のように case を省略した書き方があったり

def foo(...)
in args: [name]
  puts name
in args: [first_name, last_name]
  puts "Hi there #{first_name} #{last_name}"
in kwargs: {greeting:}
  puts "Hello #{greeting}"
else
  puts "No match: #{args}"
end

また、既存の 1行メソッド定義で以下のようにかけたりなどいろいろな書き方がでてきていて面白いですねー。

def foo(*args, **kwargs, &block) = case { args:, kwargs:, block: }
in args: [name]
  puts name
in args: [first_name, last_name]
  puts "Hi there #{first_name} #{last_name}"
in kwargs: {greeting:}
  puts "Hello #{greeting}"
else
  puts "No match: #{args}"
end

foo "Hi"                # => Hi
foo "Brad", "Gessler"   # => Hi there Brad Gessler
foo greeting: "Brad"    # => Hello Brad

いずれの書き方も面白いとは思いつつ、現状の構文と比べてできないことができるようになるわけではないのでなんかもっといい感じの拡張機能がほしいですね。

関連

GitHubで編集を提案

Discussion