Ruby はメソッド名にエイリアス(別名)が多い言語です。
例えば Enumerable
の map
と collect
の二つはエイリアスの関係にあり,どちらを使っても同じ結果になります。
そこで,どちらを使うかは好みの問題となり,「map 派」「collect 派」という言葉まで生まれてしまいました。
では,メソッドに複数の名前があったとき,本当にどれを使っても同じなのでしょうか。
そうとも言い切れない例があります。
Integer には,「レシーバーに 1 足した数を返す」メソッドがあり,next
,succ
という二つの名前を持っています。
エイリアスなので機能はもちろん変わらないのですが,速度が違います。
benchmark_driver というベンチマークテスト用 gem をインストールし,
benchmark:
- 1.next
- 1.succ
という YAML ファイルを用意して,
benchmark-driver next-succ.yaml
としてみましょう。結果は
1.succ: 134563685.5 i/s
1.next: 8751120.9 i/s - 15.38x slower
のように,なんと 15 倍もの速度差が出ました。(追記参照のこと)
実験環境:
ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin17]
どうしてこんなことになるかというと,RubyVM 上で succ
にだけ何らかの最適化が入っているのだそうです。
では,絶対に next
でなく succ
を使うべきなのでしょうか。
それは場合によるでしょう。
上の結果を見ると,Integer#next
だって毎秒 800 万回以上も実行できるのです。
多数回回るループの中で使うとしても,実用的なコードでは,ループの中の他の処理に比べて遙かに軽いことがほとんどでしょう。
マイクロベンチマークでなく現実のコードで succ
と next
の違いが処理速度を左右することはそう多くはないかもしれません。
追記 2021-11-21
いま改めて同じ方法(マシンは違う)でベンチマークをとってみると,15 倍もの差はなく,2 倍程度でした。Ruby 2.6.3,2.7.4,3.0.2 ともそんな感じです。