🔖

[Bug #19530] `Array#sum` と `Enumerable#sum` で挙動に差異があるというバグ報告

2024/05/17に公開

[Bug #19530] Array#sum and Enumerable#sum sometimes show different behaviours

  • Array#sumEnumerable#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 💥
p [7.0].sum(Money.new(0))
# Ruby 3.3 => 7.0
# Ruby 3.3 => #<Money:0x000079df826c2768 @amount=7.0>
  • またこれは長期的に存在していたバグなので stable 版にはバックポートしないとのこと
  • ちなみにこの対応によって厳密に 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 型に変換できればエラーにならなくなりました
GitHubで編集を提案

Discussion