概要
さて、rubyのマニュアルを読んでいると同じ挙動だけど名前の違うメソッドがたくさん存在します。
代表としてはmap
に対するcollect
、inject
に対するreduce
などでしょうが、このあたりはRubyの元にしたCommon LispとSmalltalkに存在するメソッドの両方の名前を採用したという歴史的経緯から、今の様な状態になっています。
どちらを使うのかは宗教論争と言われていて、どちらも使った人を自分も見たことはあります。
ただ、どっちを使った方が良いのか、そろそろ決着を見てもいいと感じたので、実際にはどちらのメソッドが人気なのか調べて見ました。
ちなみに、今回の調査対象は以下の様な基準で選びました。
- bestgems.orgでランキングされている人気のgemで、ダウンロード数Top 500のコードをサンプルにする
- 各々のgemの中の
lib
ディレクトリ以下を調査の対象とした。つまりはテストのコードは集計から排除した - 動的な言語なのでどのクラスに属しているかの推論は諦めて、あくまでメソッド名の集計結果とした。
Webプログラミングのためのものが多いとは言え様々なツールが入り乱れているrubygemsのコードを集めれば、熟達したRubyistのコードでしょうし、自分なりには妥当な基準だと考えています。
集計のためのコードはgithub上に、公開しておきます。
幾つか構文解析に失敗したファイルなども出ますが、統計的に無視して良い程度だと思われます。
結果
さて、では結果を順番に見ていきましょう。
まずは一番よく目にして気になっているであろうEnumerableモジュールの中のメソッドです。
Slalltalk由来 | 使用回数 | Common Lisp由来 | 使用回数 | ||
---|---|---|---|---|---|
collect | 870 | map | 6843 | ||
inject | 982 | reduce | 222 | ||
keep_if | 10 | select! | 20 | select + select! 合計 | 1629 |
delete_if | 299 | reject! | 193 | reject + reject! 合計 | 893 |
結果としては、それぞれ傾向はあれど、どちらのメソッドも使われている状態でした。
由来とした言語には関係が見えませんね。
意外だったのはdelete_if
メソッドの方がreduce!
メソッドより多かった事ですね。
delete_if
は、実は「!」が付いていないのに破壊的メソッドという初心者が陥りがちなバグを生成する、落とし穴を持っているメソッドなので、好んで使う人がいたことに驚きですし、視覚的に分かりやすく、綴りも短いreject!
メソッドよりも多いのがなお驚きです。
ただ、「!」の無いreject
メソッドが671回使われているので、これを足し合わせるとreject
とreject!
合わせて、893回使われています。
中の実例を見ていませんが、そもそもreject
を使って破壊的なメソッドとして扱わない方向に書き改めているのかもしれませんね。
select!
メソッドこそ仕様回数20回ですが、select
メソッドは1609回と圧倒しているのもその証左でしょう。
やっぱり基本的には短くて分かりやすい名前を選んでいるという傾向に見えますが
それ以上の理由は見えない感じですね。
inject
とreduce
に関しては、inject
の方がよく使われていますが、これに関しては書籍ではinject
を使う例が多いのが理由と推測できますね。
それでは、その他のメソッドに関して順番に見ていきましょう。
メソッド名に関しては短い名前の方を先に掲載して、長い名前の方を続いて並べました。
仕様回数の多いメソッドから順番に掲載していっています。
順位 | 短い名前のメソッド | 使用回数 | 長い名前のメソッド | 使用回数 |
---|---|---|---|---|
1 | each | 11728 | each_pair | 378 |
2 | is_a? | 7404 | kind_of? | 919 |
2 | size | 4055 | length | 2799 |
4 | send | 3183 | __send__ | 440 |
5 | marge! | 2727 | update | 506 |
6 | dup | 2471 | clone | 369 |
7 | path | 1926 | filename | 228 |
8 | key? | 1723 | has_key? | 1173 |
9 | select | 1609 | find_all | 172 |
10 | pos | 1334 | tell | 13 |
11 | fail | 932 | raise | 14119 |
12 | class_eval | 703 | module_eval | 469 |
13 | pwd | 220 | getwd | 10 |
14 | next | 215 | succ | 21 |
15 | abs | 192 | magnitude | 1 |
16 | flat_map | 191 | collect_concat | 0 |
17 | to_enum | 160 | enum_for | 86 |
18 | local | 92 | mktime | 1 |
19 | tty? | 74 | isatty | 2 |
20 | class_exec | 26 | module_exec | 10 |
21 | rmdir | 15 | unlink | 136 |
22 | conj | 6 | conjugate | 0 |
23 | imag | 5 | imaginary | 0 |
24 | gm | 4 | utc | 279 |
25 | eof | 3 | eof? | 128 |
26 | value? | 8 | has_value? | 5 |
27 | iterator? | 0 | block_given? | 1505 |
先ほども言いましたが、一般的な傾向としては、短い名前のメソッドの方がよく使われているし、使用頻度の高いメソッドほどその傾向があるという感じでしょうか、ただ例外も多いです。
例えばraise
とfail
、iterator?
とblock_given?
は圧倒的な差で綴りの長い方が使われています。
iterator?
はそもそも公式ドキュメントで使用が推奨されていないという理由がありますし、raise
は公式ドキュメントでそちらを紹介しているのでこれも分かります。
また、File#eof
とFile#eof?
に関しては、ファイルの終端に達しているかどうかを調べるメソッドですが、値がBooleanを返すため末尾に?の付くFile#eof?
が圧倒的に好まれています。
ハッシュに指定したキーが存在しているかを調べるHash#key?
とHash#has_key?
は、それぞれ1723回と1173回と、名前の長さの違いの割に2倍以下の使用回数の差に収まっています。
これだけの綴りの長さの差があってもやはり、key?
だけでは「持っている」いうニュアンスが抜けてしまうのが気になるのでしょうね。
Module#class_eval
とModule#module_eval
も1文字程度の文字の違いを気にするよりは、使われる文脈がclassとmoduleどちらの内側で使われているかで使い分ける方が良いという風に考えられているのでしょう。
使用回数に大した差が見られません。
上記の様に、名前の短いことは好まれる理由の一つですが、論理と名前の整合性で違和感が表に出るものは、名前の長さよりもそちらが優先される。
また、Rubyの公式ドキュメントのサンプルコードでどちらが使われているかは大きな判断材料になっている状態で、全体像は若干複雑な様子です。
結論
さて、Rubyで人気のメソッドを参考に比較を行って見ましたが、個人的な結論としては調べて見た感じとして、使用回数に5倍以上の開きがあるものに関しては、勝負は決したとして人気のある方にみんなもう寄せてしまっていいのではないかな、という印象を受けました。
あくまで私感ですが。
今回、調べて見て他にも面白い事が見つかっていますが、まぁそれに関しては別の記事で扱うのが良いでしょう。
何かしら参考にしていただけたなら幸いです。