2021/11/11 今回の気になった bugs.ruby のチケット
今週は Time.at
のパフォーマンス低下の報告などがありました。
[Bug #18293] Time.at in master branch was 25% slower then Ruby 3.0
Time.at
が3.0.2
と3.1.0-dev
と比較して 25% 遅くなったというバグ報告- 実際の比較はチケットを見てね!
- 原因としては実装を
time.c
からtimev.rb
に移動させたのが原因らしい - 実際にパフォーマンスが影響しているユースケースとして Shopify のキャッシュシリアライザーのケースが上げられている
- https://bugs.ruby-lang.org/issues/18293#note-4
- 数百〜数千のレコードをキャッシュする場合
Time.at
が総リクエスト時間の 2~3% を占めることは珍しくないとのこと
- これは
Time.at
のデフォルト引数が複雑なのが要因になっているらしい
[Bug #18292] 3.1.0-dev include
cause Module to be marked as initialized
- 開発版だと次のコードでエラーになってしまうというバグ報告
Module
を継承してinclude
した後にsuper
を呼ぶとエラーになってしまうぽい?- [#17048] が原因かも?と書かれてはいる
class Mod1 < Module def initialize(...) super end end p Mod1.new # => #<Mod1:0x000055b6dc5a5d00> class Mod2 < Module def initialize(...) include Enumerable super end end p Mod2.new # 3.0.2 => #<Mod2:0x000055b6dc5a59e0> # 3.1.0-dev => error: `initialize': already initialized module (TypeError)
- ちなみに以下のコードだけでもエラーになったので
include
後にModule#initialize
を呼ぶとダメなのかも
class Mod2 < Module def initialize(...) include Enumerable super end end p Mod2.new # 3.0.2 => #<Mod2:0x000055b6dc5a59e0> # 3.1.0-dev => error: `initialize': already initialized module (TypeError)
[Bug #18329] Calling super to non-existent method dumps core
- 存在しない
super
を呼び出すとコアダンプするというバグ報告- 次のコードを Ruby 3.0 以降で実行すると segv する
module Probes def self.included(base) base.extend(ClassMethods) end module ClassMethods def probe(*methods) prepend(probing_module(methods)) end def probing_module(methods) Module.new do methods.each do |method| define_method(method) do |*args, **kwargs, &block| super(*args, **kwargs, &block) end end end end end end class Probed include Probes probe :danger!, :missing def danger! raise "BOOM" end end 5.times do subject = Probed.new subject.danger! rescue RuntimeError subject.missing rescue NoMethodError end
- ちょっと分かりづらいので最小構成にすると以下のような感じ
class Probed def self.probing_module(methods) Module.new do methods.each do |method| define_method(method) do |*args, **kwargs, &block| super(*args, **kwargs, &block) end end end end prepend probing_module [:danger!, :missing] def danger! end end subject = Probed.new subject.danger! # ここで存在しない super を呼び出している subject.missing rescue NoMethodError # ここで segv subject.danger!
- なんもわからねえ
[Feature #16252] Hash#partition should return hashes
Hash#partition
の戻り値はArray
を返しているがHash
を返すようにする提案
{1=>2,3=>4}.partition{ |k,| k==1 } # 期待する挙動 => [{1=>2}, {3=>4}] # 実際の挙動 => [[[1, 2]], [[3, 4]]]
Hash#select
やHash#reject
はHash
を返しているのでそれに合わせたいらしい
{ 1=>2,3=>4,5=>6 }.select{ |k, v| k == 1 } # => {1=>2} { 1=>2,3=>4,5=>6 }.reject{ |k, v| k == 1 } # => {3=>4, 5=>6}
#partition
はEnumerable
で実装されているけど#select
や#reject
はHash
で実装されているのでその差異ですかね?