2020/11/14 今週の気になった bugs.ruby のチケット

内容は適当です。
今週と言っても今週みかけたチケットなだけでチケット自体は昔からあるやつもあります。
あくまでも『わたしが気になったチケット』で全ての bugs.ruby のチケットを載せているわけではありません。

Pattern matching is no longer experimental

  • bugs.ruby ではなくて commit
  • パターンマッチが experimental ではなくなった
  • 右代入は experimental になるので注意
# no warning
case { name: "homu", age: 14 }
in { name:, age: }
end

# warning: One-line pattern matching is experimental, and the behavior may change in future versions of Ruby!
{ name: "homu", age: 14 } => { name:, age: }

[Feature #17176] GC.auto_compact / GC.auto_compact=(flag)

[Feature #17294] Feature: Allow method chaining with Pathname#mkpath Pathname#rmtree

# Pathname のインスタンスを生成しつつ mkpath でディレクトリも作成したい
# #mkpath の戻り値は nil なので tap を経由する必要がある
path = Pathname.new("/tmp/new").tap(&:mkpath)
  • Pathname#mkpath の戻り値をレシーバにすることで次のようにかける
path = Pathname.new("/tmp/new").mkpath

[Feature #17312] New methods in Enumerable and Enumerator::Lazy: flatten, product, compact

  • Enumerator::Lazy#compact #product #flatten を追加する提案
  • あると便利そう

[Feature #17314] Provide a way to declare visibility of attributes defined by attr* methods in a single expression

  • 以下の2つの変更を提案するチケット
  • attr_xxx の戻り値を引数の名前の配列にする提案
attr_reader :id, :name, :age
# 今   => nil
# 提案 => [:id, :name, :age]
  • public/protected/private の引数に配列を渡せるようにする提案
# 提案
private [:id, :name, :age]
  • この2つを取り入れると以下のように private + attr_xxx を組み合わせる事ができる
class Foo
  private attr_accessor :foo, :bar
end
# 独自のラッパーメソッドを介したりとか
class Module
  def traceable(names)
    # ...
    names
  end
end

class Foo
  traceable attr_accessor :foo
  # it can be mixed with public/protected/private too
  protected traceable attr_accessor :bar
end

[Feature #17316] On memoization

  • Ruby でメモ化する場合、以下のようなコードを書く場合が多い
@foo ||= some_heavy_calculation(...)
  • しかし、厳密には以下のように『インスタンス変数が定義されているかどうか』で判定する必要がある
unless instance_variable_defined?(:foo)
  @foo = some_heavy_calculation(...)
end
  • こういうコードは冗長であまり書きたくないのでもっと簡略化して書きたいという提案
  • 例えば以下のように #instance_variable_set でブロックを受け取るようにしたりとか
instance_variable_set(:foo){ some_heavy_calculation(...) }
  • もしくは #memoize みたいなヘルパメソッドを定義するとか
memoize(:foo){ some_heavy_calculation(...) }
  • 機能としては欲しいんだけど、どういうような書き方にするのかは無限にむずかしそう…

[PR #3740] Speed up ivar set

  • 仕組みはわからないがインスタンス変数の割当周り?速度が早くなった PR
  • ベンチマークはこんな感じ
    • 下の方に書いてある Ruby のコードが早くなった
aaron@whiteclaw ~/g/ruby (init-ivars)> ruby -v test.rb
ruby 3.0.0dev (2020-11-05T19:13:04Z master ab5f2fa4fb) [x86_64-linux]
Warming up --------------------------------------
                init   523.589k i/100ms
Calculating -------------------------------------
                init      5.281M (± 0.4%) i/s -     26.703M in   5.056507s
aaron@whiteclaw ~/g/ruby (init-ivars)> ./ruby -v test.rb
ruby 3.0.0dev (2020-11-06T18:37:08Z init-ivars 014059c3cb) [x86_64-linux]
Warming up --------------------------------------
                init   547.661k i/100ms
Calculating -------------------------------------
                init      5.444M (± 0.4%) i/s -     27.383M in   5.030236s
aaron@whiteclaw ~/g/ruby (init-ivars)> cat test.rb
require "benchmark/ips"

class Foo
  def initialize
    @a = nil
    @b = nil
    @c = nil
    @d = nil
  end
end

Benchmark.ips do |x|
  x.report("init") { Foo.new }
end

[Feature #17322] Deprecate Random::DEFAULT and introduce Random.default() method to provide Ractor-supported default random generator

  • デフォルトの疑似乱数生成器を返す Random::DEFAULT という定数がある
  • これはスレッドセーフではないため Ractor ごとに疑似乱数生成器が参照できないぽい
    • 複数の Ractor から参照するとエラーになる
  • 複数の Ractor で利用できるように Random.default() というメソッドを新しく追加する提案
  • それに伴い Random::DEFAULT は Deprecate にする
    • なので Ractor ないでは Random::DEFAULT はしないようにする
  • Thread#[] みたいに Ractor ごとの固有の変数を定義するようにしてはどうか、とコメントがある

[Feature #17315] Hash #transform

  • Hash の要素を変更して Hash を返す Hash#transform メソッドの提案
h = {'name' => 'dominic ', 'email' => 'dominic.mail.com '}
# キーを String から Symbol に変換する
h.transform!{|k,v| [k.to_sym, v.strip]}
h # => {name: 'dominic', email: 'dominic.mail.com'}
  • Hash#map だと Hash ではなくて Array を返すので Hash を返すメソッドはほしい
  • 一応、副作用がない版は Hash#to_h でも代用可能
h = {'name' => 'dominic ', 'email' => 'dominic.mail.com '}
# キーを String から Symbol に変換する
p h.to_h { |k,v| [k.to_sym, v.strip] }
# => {:name=>"dominic", :email=>"dominic.mail.com"}
# レシーバは元のまま
p h
# => {"name"=>"dominic ", "email"=>"dominic.mail.com "}
  • なるほどね?

merge, fix されたチケット