LoginSignup
0
0

More than 3 years have passed since last update.

ActiveSupportのArray#sumは七変化する

Posted at

Railsエンジニアなら必ずお世話になるActiveSupportはRubyデフォルトの Array#sumを拡張する処理が含まれている。
とあるライブラリ開発でActiveSupportの実装を追いかけた時に見つけた #sumの挙動をまとめます。

[1,2,3].sum

おそらくは1番標準的な使い方。

[5, 15, 10].sum                                                                       
=> 3

ちなみにこの使い方はActiveSupportを使わなくても使用できる。
昔はRuby標準の Array#sumよりActiveSupportの Array#sumのほうが高速に動作したがある時期を持って本家に取り込まれたそうで今はどっちも同じ早さという話

['foo', 'bar'].sum

ActiveSupport無しだとエラーになる↓


pry(main)> ['foo', 'bar'].sum
TypeError: String can't be coerced into Integer
from (pry):1:in `+'

ところがActiveSupportありだとこうなる

pry(main)> ['foo', 'bar'].sum
=> "foobar"

唐突に +Array.joinに化けた。
そうは言ってもRubyで文字列を + すると連結できるのでこの挙動自体が理解できないわけではない。

[[1,2,3], [4,5]].sum

先の例同様にActiveSupport無しだとエラーになる

pry(main)> [[1,2,3], [4,5]].sum
TypeError: Array can't be coerced into Integer
from (pry):2:in `+'

じゃあActiveSupportありだとどうなるのか?
こうなります

pry(main)> [[1,2,3], [4,5]].sum
=> [1, 2, 3, 4, 5]

もしかしたら Array.flatten.sumと同じ挙動になると予想された人もいたのではないでしょうか?
残念なことに結果は sumされません。代わりに flattenされます。なんで...?

おまけ

ArrayじゃなくHashでsumしたらどうなるだろうか?

pry(main)> {a: 10, b: 20}.sum
=> [:a, 10, :b, 20]

!?!?!?
ソースコードを見てると以下の記述を発見

  # We can't use Refinements here because Refinements with Module which will be prepended
  # doesn't work well https://bugs.ruby-lang.org/issues/13446

なるほどぉ...

0
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0