📝

[Feature #19764] パターンマッチを利用して呼び出されるメソッドをオーバーロードする提案

2024/05/07に公開

[Feature #19764] Introduce defp keyword for defining overloadable, pattern matched methods

  • 以下のようにパターンマッチを利用して呼び出されるメソッドをオーバーロードしたいという提案
    • 同名のメソッドを複数定義できる
    • どのメソッドが呼び出されるのかはパターンマッチで制御する
defp call(String => s unless s in /^[a-z]/)
  puts "string: #{s.inspect} (capitalized)"
end

defp call(String => s)
  puts "string: #{s.inspect}"
end

defp call(Hash(foo:, bar:) => h)
  puts "hash: #{h.inspect}"
end

defp call(**nil)
  puts "no keyword args"
end

call("Example") # => string: "Example" (capitalized)
call("test")    # => string: "test"
call(foo: 1, bar: 2)
# => hash: { :foo => 1, :bar => 2 }
  • 上は以下のような疑似コードになる
    • case ... は実際にかけないので動かない
def call(...)
  case ...
  in String => s unless s in /foo/
    puts "string: #{s.inspect} (not foo)"
  in String => s
    puts "string: #{s.inspect}"
  in Hash(foo:, bar:) => h
    puts "hash: #{h.inspect}"
  in **nil
    puts "no keyword args"
  else
    raise NoMatchingMethod
  end
end
  • コメントでは メソッドのオーバーロードメソッドシグネチャ内のパータンマッチ を別々に考える必要があると書いてある
  • 後者に関しては以下のように利用したいと書いてある
def foo(nb => Integer)      # class validation
def foo(minutes => 0..59)   # range/structure validation
def foo(if: => condition)   # alias for keyword argument (#18402)
def foo(v => @hostname)     # DRY way to set instance variables (#15192 and many others)
  • オーバーロードに関してはモンキーパッチを書かずにメソッドを拡張する事ができるので個人的にはあると便利
    • 便利ではあるけどどこでどのメソッドが定義されているのかわからなくなる事もあるのでデメリットもある
  • 引数に対してパターンマッチがかけるのも個人的にはめっちゃほしいけど、どういう感じで構文を考えるのかはむずかしそう
    • 結局メソッドの中でパターンマッチかけばいいだけではあるので複雑な構文を導入してまでほしいのか?と言われるとウーン
GitHubで編集を提案

Discussion