2022/07/22 今回の気になった bugs.ruby のチケット
今週は Time.new
に 24時
を指定してタイムゾーンを渡した時に意図しない結果が返ってくるバグチケットがありました。
[Bug #18929] ruby master looks slower than 3.1 on a micro benchmark of short-lived objects
$ time ruby -ve '10000000.times { Object.new }' ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux] real 0m2.503s user 0m2.484s sys 0m0.016s $ time ./local/bin/ruby -ve '10000000.times { Object.new }' ruby 3.2.0dev (2022-07-20T00:40:59Z master e330dceb3f) [x86_64-linux] real 0m3.074s user 0m3.016s sys 0m0.052s
- https://github.com/ruby/ruby/commit/85479b34f76d5b426c2a8224d8ed6d8c2ad81ca2 のコミットがトリガーになっているらしいが、これを戻してもパフォーマンスは戻らなかったらしい
- 謎い…
- 修正PR: https://github.com/ruby/ruby/pull/6156
[Bug #18927] Can't access class variable directly with class inheritance
- 以下のように親クラスから子クラスのクラス変数にアクセスする事はできない
class Parent def self.class_var @@class_var end end class Child < Parent @@class_var = "class_var" end # error: uninitialized class variable @@class_var in Parent (NameError) p Child.class_var
- しかし、以下のように
class_variable_get
を使用すると子クラスのクラス変数を取得する事ができる
class Parent def self.class_var # class_variable_get だとアクセスする事ができる class_variable_get(:@@class_var) end end class Child < Parent @@class_var = "class_var" end p Child.class_var # => "class_var"
- このように
@@class_var
とclass_variable_get(:@@class_var)
で挙動が違うがこれは意図する挙動なのか?というチケットになる - クラス変数は自身とサブクラスでのみ参照できるのが期待する挙動になる
- また以下のようにコメントされている
It's best to avoid using class variables completely in Ruby. # 訳: Rubyでは、クラス変数を完全に使わない方がよいでしょう。
[Feature #18930] Officially deprecate class variables
- 上の [Bug #18927] からの派生でクラス変数は紛らわしいので公式で非推奨にする提案
- 具体的にはドキュメントに明記したりとか
Warning[:deprecation] = true
の場合にのみ警告を出したりとか
- 具体的にはドキュメントに明記したりとか
- だいたいの場合はインスタンス変数で代替できるのでクラス変数がなくてもそんなに困らないとは思うんですが、既存のコードに対する影響はかなり大きそうですねえ
[Bug #18837] Not possible to evaluate expression with numbered parameters in it
- 以下のように
binding
経由で元のブロックの引数を参照する事ができる
def dumper(bnd) puts bnd.local_variable_get 'i' puts bnd.eval 'i * 10' end [1,2].each { |i| dumper(binding) }
- しかし
_1
の場合はBinding#eval
で参照することができない
def dumper(bnd) puts bnd.local_variable_get('_1') puts bnd.eval '_1 * 10' end [1,2].each do # この行がないと local_variable_get でも _1 を参照する事ができない some = _1 dumper(binding) end
- 最適化のために実際の引数を削除する可能性があるのであとから
_1
を参照するのは難しい、という旨のコメントなどがされている
[Bug #18922] Time at 24:00:00 UTC is not normalized
Time.new
でタイムゾーンを指定して24時
を指定した場合に意図しない挙動になっているバグ報告
# TimeZone を渡さない場合は問題ない # 次の日の0時になっている pp Time.new(2000, 1, 1, 24, 0, 0) # => 2000-01-02 00:00:00 +0900 # TimeZone を渡した場合に意図しない時刻が返ってくる pp Time.new(2000, 1, 1, 24, 0, 0, "UTC") # => 2000-01-01 23:00:00 UTC # 内部では 2000/01/01 24:00:00 というような情報を持っている pp Time.new(2000, 1, 1, 24, 0, 0, "UTC").to_a # => [0, 0, 24, 1, 1, 2000, 7, 0, true, "UTC"]
- 開発版ではこの問題は既に修正済み
pp RUBY_VERSION # => "3.2.0" pp Time.new(2000, 1, 1, 24, 0, 0, "UTC") # => 2000-01-02 00:00:00 UTC pp Time.new(2000, 1, 1, 24, 0, 0, "UTC").to_a # => [0, 0, 0, 2, 1, 2000, 1, 1, true, "UTC"]
- これってそもそも
24
を指定できるのがバグの温床なのではなかろうか…- るりまだと
0 ~ 23
を指定できると書いてはあたt - https://docs.ruby-lang.org/ja/latest/method/Time/s/new.html
- RDoc でも同様
- るりまだと
[Bug #18038] Invalid interpolation in heredocs
- 以下のようにヒアドキュメントで式展開をした時に意図しない結果になっているというバグ報告
pp RUBY_VERSION # => "3.0.4" var = 1 # 式展開されない v1 = <<~CMD something #{"/#{var}"} CMD # 式展開される v2 = <<~CMD something #{other = "/#{var}"} CMD # 式展開されない v3 = <<~CMD something #{("/#{var}")} CMD p v1 # => "something\n/\n" p v2 # => "something\n/1\n" p v3 # => "something\n/\n" p v1 == v2 # => false p v2 == v3 # => false