🙆
[Bug #20640] Ruby 3.0 から **kwd しつつ kwd.delete したときの挙動が壊れているバグ報告
[Bug #20640] Evaluation Order Issue in f(**h, &h.delete(key))
- Ruby 3.0 からキーワード引数で Hash を渡しつつブロック引数で
Hash#delete
を呼び出したときの評価順が壊れているというバグ報告 - 以下のように
**hass
しつつ&hash.delete
すると Ruby 3.0 から挙動が変わります
def check(**kwd, &block)
kwd
end
kwd = { a: proc {} }
# kwd をキーワード引数で渡しつつ、ブロック引数で #delete した値を渡す
# Ruby 3.0 以降では delete した後の値が kwd に渡される
pp check(**kwd, &kwd.delete(:a))
# Ruby 3.0 以前 => {:a=>#<Proc:0x00007c0154fa8f58 /tmp/vrD7Av9/27:6>}
# Ruby 3.0 以降 => {}
- また位置引数がある場合は Ruby 3.3 から挙動が変わります
def check(*args, **kwd, &block)
kwd
end
args = []
kwd = { a: proc {} }
# こっちは位置引数も渡す
pp check(*args, **kwd, &kwd.delete(:a))
# Ruby 3.3 以前 => {:a=>#<Proc:0x00007c0154fa8f58 /tmp/vrD7Av9/27:6>}
# Ruby 3.3 以降 => {}
- Ruby では
*
**
する前に値をコピーして渡すのが期待する挙動なので以前と同じような挙動になるように修正される予定
def check(*args, **kwd, &block)
kwd
end
kwd = { a: proc {} }
# 以下が期待する挙動になる
pp check(**kwd, &kwd.delete(:a))
# {:a=>#<Proc:0x00007c0154fa8f58 /tmp/vrD7Av9/27:6>}
args = []
kwd = { a: proc {} }
# こっちは位置引数も渡す
pp check(*args, **kwd, &kwd.delete(:a))
# {:a=>#<Proc:0x00007c0154fa8f58 /tmp/vrD7Av9/27:6>}
Discussion