💬
Ruby 3.4 から **nil が許容されるようになった + ちょっとした非互換
Ruby 3.4 で **nil
が許容されるようになりました。
これにより以下のような **obj
をするときに obj
が nil
であるかどうかを気にする必要がなくなります。
opt = nil
# opt が nil でも問題ない
# この場合は **{} と同等になる
func(**opt)
# Ruby 3.4 => error: no implicit conversion of nil into Hash (TypeError)
# Ruby 3.4 => OK
nil.to_hash
が定義されたわけではない
**
構文は内部で #to_hash
メソッドが呼ばれて Hash として変換されます。
なので #to_hash
が定義されているオブジェクトであれば **
が利用できます。
class X
def to_hash
{ value: 42 }
end
end
x = X.new
# ** すると内部で #to_hash が呼ばれ、その結果に置き換えられる
pp(**x)
# => {:value=>42}
なので nil.to_hash
が定義されていれば Ruby 3.4 でも **nil
は利用できるんですが、今回の対応では特に nil.to_hash
が追加されたわけではなくて内部処理として処理されるようになった感じです。
nil.to_hash
# Ruby 3.3 => undefined method `to_hash' for nil (NoMethodError)
# Ruby 3.4 => undefined method `to_hash' for nil (NoMethodError)
更に言うと Ruby 3.4 からは『 nil.to_hash
が呼び出されなくなった』とも言えそうです。
class NilClass
def to_hash
pp "Hoge"
{}
end
end
{ **nil }
# Ruby 3.3 => "Hoge"
# Ruby 3.4 => no output
なので Ruby 3.4 以前で『 **nil
を呼び出したときに nil.to_hash
が呼び出されていること』を期待しているコードがあれば非互換になってしまうので注意する必要があります(まあ無いとは思いますが…。
Discussion