
Issue #19530 has been updated by byroot (Jean Boussier). Looking at `Array#sum` implementation, it very clearly has a fast path for when all the elements of the array are native numeric types, with a fallback for other objects. But it also doesn't check the initial value type before going in the fast path. That should be easy enough to fix. ---------------------------------------- Bug #19530: `Array#sum` and `Enumerable#sum` sometimes show different behaviours https://bugs.ruby-lang.org/issues/19530#change-102388 * Author: dstosik (David Stosik) * Status: Open * Priority: Normal * ruby -v: ruby 3.2.1 (2023-02-08 revision 31819e82c8) [arm64-darwin22] * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- 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)) #=> #<Money:0x00000001005b35f0 @amount=7.0> p [7.0] .sum(Money.new(0)) #=> 7.0 💥 ``` 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/a...) 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. -- https://bugs.ruby-lang.org/