🔖
[Bug #19530] `Array#sum` と `Enumerable#sum` で挙動に差異があるというバグ報告
[Bug #19530] Array#sum
and Enumerable#sum
sometimes show different behaviours
-
Array#sum
とEnumerable#sum
で挙動に差異があるというバグ報告 - Ruby 3.2 時点では以下のような挙動になり
#sum
の戻り値が異なります
class Money
def initialize(amount)
@amount = amount.to_f
end
def +(other)
self.class.new(@amount + other.to_f)
end
def to_f
@amount
end
end
p [7.0].each.sum(Money.new(0)) #=> #<Money:0x00000001005b35f0 @amount=7.0>
p [7.0] .sum(Money.new(0)) #=> 7.0 💥
- これは
Array#sum
で最適化する処理が意図してない挙動になっているのが原因みたいですね - このバグ自体は Ruby 3.3 で修正されています
p [7.0].sum(Money.new(0))
# Ruby 3.3 => 7.0
# Ruby 3.3 => #<Money:0x000079df826c2768 @amount=7.0>
- またこれは長期的に存在していたバグなので stable 版にはバックポートしないとのこと
- https://bugs.ruby-lang.org/issues/19530#note-6
- なので 3.2.x などには反映されない予定
- ちなみにこの対応によって厳密に
Array#sum
の引数の型を見るようになったので以下のような違いもあります
class X
def +(other)
to_i + other
end
# 暗黙的に Integer に変換されるようにメソッド定義しておく
def to_i
5
end
end
# こっちは元々 Ruby 3.2 系でも動いていた
p [3].each.sum(X.new)
# => 8
# この挙動が変わった
p [3].sum(X.new)
# Ruby 3.2 => error: X can't be coerced into Integer (TypeError)
# Ruby 3.3 => 8
- 修正後は
#sum
の引数が Integer 型に変換できればエラーにならなくなりました
Discussion