collect は Enumerable#collect だが collect! は Array#collect! だった

Rubyのドキュメントを見て、「あれ? Arrayでcollectが定義されているぞ。eachから派生するイテレータ*1はEnumerableで定義するんじゃなかったか?」と思ったが、よく見たらexclamation markが付いていた。collect!、つまり破壊的メソッドだ。破壊的なイテレータは、Enumerableをインクルードするクラスの方で定義するようだ。


そういう目でドキュメントを眺めると、

  • Enumerableで定義しているイテレータはどれも破壊的ではない
  • 一方、ArrayやHashで定義しているイテレータは、それらクラスに特有の処理をもつか(Hash#each_key など)、あるいは破壊的であるか(Array#collect! など)、のどちらかの性質を持つものが多い

ということがわかる。おそらく、破壊的メソッドはクラスの持つデータ構造に依存するから、Enumerableで定義するのは無理だということだろう。

余談だが、MatrixクラスはEnumerableをインクルードしていない(eachメソッドがないため)。よって非破壊的なcollectでも当然、Matrix#collectとなっている。

*1:正確には「ブロック付メソッド呼び出し」。