2022/04/14 今回の気になった bugs.ruby のチケット
今週は Kernel#then に引数を渡せるようにする提案がありました。
[Feature #18690] Allow Kernel#then to take arguments
Kernel#thenに引数を追加する提案- 通常はレシーバをブロックの引数として受け取るが
1.5.then{|x| Math.atan(x)}
#thenに渡した引数をブロックの引数でも受け取るようにする提案
3.then(4){|x, y| Math.hypot(x, y)}
- チケットでは
honyarara.then{|x|
foo(x)
bar(fugafugafuga)
baz(hogehogehoge)
qux(x, fugafugafuga, hogehogehoge)
}
- の場合に
honyarara.then(fugafugafuga, hogehogehoge){|x, y, z|
foo(x)
bar(y)
baz(x)
qux(x, y, z)
}
- とかけるユースケースが提示されている
thenの中で複数回同じメソッドを呼ぶ場合だと便利そうですかね?
obj.bar.then(hoge.foo) { |bar, foo| foo.piyo(foo, bar, foo) }
[Bug #18688] when array's default value is empty hash adding a hash key value changes all array elements
- 以下のように空の Hash の配列の要素を書き換えると全て書き変わってしまうというバグ報告
# {} が3つある配列を生成する ah = Array.new(3, {}) p ah # => [{}, {}, {}] # 1つの要素を書き換える ah[1][:foo] = 'bar' # この時に配列の要素は以下のようになる p a # 期待する挙動 => [{}, {:foo=>"bar"}, {}] # 実際の挙動 => [{:foo=>"bar"}, {:foo=>"bar"}, {:foo=>"bar"}]
- これは配列の要素の参照先が全て同じになっているので意図する挙動になる
# これは参照しているオブジェクトがバラバラ a = [{}, {}, {}] p a[0].__id__ # => 60 p a[1].__id__ # => 80 p a[2].__id__ # => 100 # Array.new の場合は全て同じオブジェクトを参照している a = Array.new(3, {}) p a[0].__id__ # => 120 p a[1].__id__ # => 120 p a[2].__id__ # => 120 # n 個の同じ要素の配列を定義したい場合はブロックを渡して定義するのが安全 a = Array.new(3) { {} } p a[0].__id__ # => 60 p a[1].__id__ # => 80 p a[2].__id__ # => 100
[Feature #18685] Enumerator.product: Cartesian product of enumerables
- 要素ごとの全ての組み合わせの
Enumeratorを生成するEnumerator.productを追加する提案
product = Enumerator.product(1..3, ["A", "B"]) p product.class #=> Enumerator product.each do |i, c| puts "#{i}-#{c}" end =begin output 1-A 1-B 2-A 2-B 3-A 3-B =end
Array#productはあるんですがそれとは別にEnumerableでも使いたいって感じですかね
# Enumerable に対しては使えないので Array に変換する必要がある pp (1..3).to_a.product(["A", "B"]) # => [[1, "A"], [1, "B"], [2, "A"], [2, "B"], [3, "A"], [3, "B"]]
[Feature #18618] no clobber def
- 以下のようにスーパークラスのメソッドがある場合は再定義しないようなコードがある
class Dog def bark 'bark!' end end class Poodle < Dog # 既に同名のメソッドが定義されていれば例外にする raise if method_defined? :bark def bark 'bow-wow' end end
- これを次のように
ncdefでかけるようにしたいという提案
class Dog def bark 'bark!' end end class Poodle < Dog ncdef bark # "no clobber" def 'bow-wow' end end # => #<MethodAlreadyDefined: Method `bark' already defined.>
ApplicationRecordとかのサブクラスを定義したい時にこういうことをしたいらしい- 意図しないメソッドの上書きってどれぐらい弊害があるんですかね…
- これがあると全部
ncdefで定義する必要がありそう
- これがあると全部
- 他の言語だと逆に『スーパークラス側でメソッドが上書きできないこと』を明示化するような機能は存在する
- C++ の例だと以下のような感じ
// 基底クラス class base { // final が付いていると派生クラスで再定義できない virtual void func_final() final; }; // 派生クラス class sub : base { // error: error: declaration of 'func_final' overrides a 'final' function virtual void func_final() final; };
- sorbet だと
finalをサポートしているらしい