厳密には、言語とコンパイラおよびコンパイラオプションによりますが、呼び出す関数(メソッド)が高コストの場合は一般的に速くなります。
質問にあるコードですとstr.indexOf("<")
がとても重い処理であれば、速度は大きく異なります。なぜなら、上のコードは3回呼び出されるのに対し、下のコードは1回しか呼び出されないからです。最適化がなければコードの通りに呼び出されますので、回数が多くなる方が不利になります。とくに最適化ができないスクリプト言語ではこの速度の違いが顕著に表れるます。
場合によっては、最適化によって呼び出しが一回で済むようにコンパイラが書き換えてくれるときがあります。ただし、それは、対象が参照透過である時のみです。なぜなら、もし関数が、その評価により何かの値が変わる(副作用)、または、呼び出し毎に結果が変わる、といった場合(つまり、参照透過ではない場合)、呼び出し回数によって動作が変わる可能性があるからです。逆に、そのような副作用や別の値になる可能性が無い場合は、わざわざ律儀に何回も呼び出さず、1回目の結果を再利用する形で最適化してくれます。
Haskellで例を示します。(ソースコード名はtest.hsとしています)
Haskell
1import Debug.Trace
2plpl a b = trace "call..." $ a + b
3main = print $ (plpl 3 5) + (plpl 3 5)
plpl
関数はただの足し算ですが、デバッグ用のtrace
関数により、呼び出したときは"call..."というメッセージを出すようにしています。これによってplpl
関数が何回呼び出されたかが判断できます。実際にrunhaskell(Haskellのインタプリンタ)で実行すると下記のようになります。
$ runhaskell test.hs
call...
call...
16
plpl
はmain
内で2回書いているので、コードの通り2回呼び出されました。では、今度はちゃんとコンパイルします。(-Oは最適化オプションです)
$ ghc -O test.hs
[1 of 1] Compiling Main ( test.hs, test.o )
Linking test ...
$ ./test
call...
16
plpl
は参照透過であり※、その引数も同じ3と5ですので、コンパイラは2回呼び出す必要は無いと判断し、1回の呼び出しだけで動作するようにしてくれました。そのため、plpl
関数は1回しか呼び出されません。
※ デバッグ用のtrace
による副作用は無かった物として扱われます。
なお、ほとんどの言語では、定数を除き、変数や関数が参照透過であることをコンパイラが判断することが難しいことがあります。そのため、上のような最適化はHaskellのような純粋関数型言語以外では過度の期待はできないでしょう。
補足
catsforepawさんの回答の例で言うと、C言語の+演算子が参照透過であることをC言語のコンパイラが知っていますので、aとbが変わらない(その範囲内でaとbが参照透過である)ことをコンパイラが判断できれば、最適化してくれます。ですが、C++のオーバーロードされた+演算子や他の一般的な関数では、インライン展開が出来るなどの条件が揃わないとその判断が困難ですので、やはり過信は禁物です。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/02/03 13:45