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
をサポートしているらしい