2020/08/13 今週の気になった bugs.ruby
内容は適当です。
今週と言っても今週みかけたチケットなだけでチケット自体は昔からあるやつもあります。
[Feature #15504] Freeze all Range object
- リテラルで
Range
を生成すると同じid
のオブジェクトが返ってくるケースがある
# これは個別の id が返ってくる p (1..3).__id__ # => 60 p (1..3).__id__ # => 80 p (1..3).__id__ # => 100 def hoge (1..3).__id__ end # これは同じ id が返ってくる p hoge # => 120 p hoge # => 120 p hoge # => 120
- これの影響で次のように奇妙な動作をすることがある
2.times{ r = (1..3) p r.instance_variable_get(:@foo) #=> 1st time: nil #=> 2nd time: :bar r.instance_variable_set(:@foo, :bar) }
- こういう奇妙な問題を回避するために
frozen
した値を返しませんか?という提案 frozen
されたRange
でも次のように中の値が変わってしまうことがある
r = ('a'..'z').freeze r.end.upcase! p r # => "a".."Z"
[Feature #17054] Some NilClass methods are faster if implemented in Ruby
NilClass#to_i
などを C言語じゃなくて Ruby で実装することで高速化するというチケット- PR みるとわかりやすい : https://github.com/ruby/ruby/pull/3366
- これは Ruby 側でメソッドをキャッシュしており、実行中に大量のメソッドを呼んだ場合に C言語実装よりも早くなるケースがあるらしい
- こういう実は C言語よりも Ruby で実装すると高速化する。みたいなのがあるのが面白い
[Bug #17101] YAML.load_file: Massive slowdown under Ruby 2.7 vs. Ruby 2.4
sh@MyComputer:~/rubydev/bugs$ benchmark-driver yml.yaml --output compare --rbenv '2.4.4;2.5.8;2.6.6;2.7.1;2.8.0-dev' Calculating ------------------------------------- 2.4.4 2.5.8 2.6.6 2.7.1 2.8.0-dev load_file 0.113 0.075 0.076 0.058 0.134 i/s - 1.000 times in 8.839451s 13.406090s 13.240691s 17.256679s 7.435239s Comparison: load_file 2.8.0-dev: 0.1 i/s 2.4.4: 0.1 i/s - 1.19x slower 2.6.6: 0.1 i/s - 1.78x slower 2.5.8: 0.1 i/s - 1.80x slower 2.7.1: 0.1 i/s - 2.32x slower
- これを見てみると
2.7.1
では遅いが2.8.0dev
ではだいぶ高速化している
[Bug #17105] A single return
can return to two different places in a proc inside a lambda inside a method
- Ruby では ブロック内で
return
したときにproc
とlambda
で挙動が異なる
# proc 内で return するとその時点でメソッドから抜ける def hoge block = proc { return :return_proc } [:return_hoge, block.call] end p hoge # => :return_proc # lambda 内で return するとそのブロックから抜ける def hoge block = lambda { return :return_lambda } [:return_hoge, block.call] end p hoge # => [:return_hoge, :return_lambda]
- しかし、次のように
lambda
内でproc
からreturn
した場合はその限りではなくなる
# lambda でラップするとメソッドからではなくて lambda から抜ける def hoge block = lambda { block = proc { # ここで return すると lambda から抜ける return :return_proc } block.call :return_lambda } [:return_hoge, block.call] end p hoge # => [:return_hoge, :return_proc] # proc でラップした場合はメソッドから抜ける def hoge block = proc { block = proc { # ここで return するとメソッドから抜ける return :return_proc } block.call :return_lambda } [:return_hoge, block.call] end p hoge # => :return_proc
- この挙動は奇妙なのでこれが意図しているのかどうか議論するチケットになっている、多分
[Feature #13560] Module#attr_ methods return reasonable values と [Feature #9453] Return symbols of defined methods for attr
and friends
attr_xxx
に戻り値を追加する提案- いまは
nil
が返ってくる
- いまは
attr_reader :hoge # => [:hoge] attr_writer :foo, :bar # => [:foo, :bar] attr_accessor :piyo # => [:piyo, :piyo=]
- これを利用すると次のようにして
attr_reader
しつつprivate
などができる
private *attr_reader :hoge, :foo
- まつもとさんとしては以下のように
private_attr_reader
みたいなメソッドを用意すればいいんじゃない?みたいなコメントをしてる
private_attr_reader :hoge, :foo