【一人 bugs.ruby Advent Calendar 2021】[Feature #16806] Struct#initialize accepts keyword arguments too by default【13日目】
一人 bugs.ruby Advent Calendar 2021 13日目の記事になります。
Struct
の keyword_init:
をデフォルトで有効にするというチケットです。
[Feature #16806] Struct#initialize accepts keyword arguments too by default
Struct
の keyword_init:
をデフォルトで有効化させるチケットです。
対応後は以下のような挙動になる想定です。
User = Struct.new(:name, :age) # これは以前の挙動のまま mami = User.new("mami", 14) pp mami # => #<struct User name="mami", age=14> # キーワード引数を渡すと keyword_init: true と同じように初期化される homu = User.new(name: "homu", age: 14) pp homu # => #<struct User name="homu", age=14>
ただし keyword_init: false
の場合でも User.new(name: "homu", age: 14)
の用に渡せる事ができます。
User = Struct.new(:name, :age, keyword_init: false) # キーワード引数ではなくて User.new({ name: "homu", age: 14 }) と同じ意味になる # なので現状だと name に Hash オブジェクトが入ってしまうので既存の挙動と変わってしまう p User.new(name: "homu", age: 14) # => #<struct User name={:name=>"homu", :age=>14}, age=nil>
デフォルトで keyword_init: true
にした場合に上のようなコードの意味が変わってしまい非互換な変更になってしまいます。
なので Ruby 3.1 ではまず keyword_init: false
に対してキーワード引数を渡すと警告を出すようにし、Ruby 3.2 で変更するような移行パスになります。
User = Struct.new(:name, :age) # Ruby 3.1 では keyword_init: true でない場合にキーワード引数を渡すと警告が出る # warning: Passing only keyword arguments to Struct#initialize will behave differently from Ruby 3.2. Please use a Hash literal like .new({k: v}) instead of .new(k: v). p User.new(name: "homu", age: 14) # => #<struct User name={:name=>"homu", :age=>14}, age=nil> # 明示的に Hash を渡した場合は警告は出ない # no warning p User.new({ name: "homu", age: 14 })
結果的に非互換にはなるんですがこれはよさそうな変更ですね。