From: "byroot (Jean Boussier) via ruby-core" Date: 2023-03-14T08:51:12+00:00 Subject: [ruby-core:112875] [Ruby master Bug#19530] `Array#sum` and `Enumerable#sum` sometimes show different behaviours 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)) #=> # 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/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. -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/