Bug #19530
Updated by dstosik (David Stosik) almost 2 years ago
Hi everyone. 👋🏻 We recently discovered that `Array#sum` and `Enumerable#sum` will output different results in some edge cases. Here's the smallest script I managed to write to reproduce the issue: ``` ruby 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)) [7.0].each.sum(Money.new(0)).class #=> #<Money:0x00000001005b35f0 @amount=7.0> Money p [7.0] .sum(Money.new(0)) .sum(Money.new(0)).class #=> 7.0 Float 💥 ``` I understand that it is expected that `#sum` may not honor custom definitions of the `#+` method (particularly when the summed values are `Float`). However, I would like to bring your attention to the fact that, in the example above, calling `#sum` on an `Array` of `Float` values and calling `#sum` on an `Enumerable` that yields the same `Float` values will return results of different types. I've reproduced the same behaviour with multiple versions of Ruby going from 2.6.5 to 3.2.1. Ideally, I would expect `[7.0].sum(Money.new(0))` to return a `Money` object identical to the one returned by `[7.0].each.sum(Money.new(0))`. I think it would make sense if at least they returned an identical value (even if it is a `Float`). Addendum: I forgot to mention [this extract](https://github.com/ruby/ruby/blob/da9c84f859db292ab1127f7ca9b7741fff06557b/array.c#L8133-L8137) of the `Array#sum` documentation: > When no block is given, returns the object equivalent to: > > ``` ruby > sum = init > array.each {|element| sum += element } > sum > ``` With the example above, it would indeed return a `Money` object.