コンパイラに判りいいってことは人間にも判りいいだろ?
ヘル勢が最適化に関心を持ったようです。(http://d.hatena.ne.jp/r_mujirushi/20070514/1179157074)(http://d.hatena.ne.jp/o_mega/20070516/1179285447)共通の引用先→http://www.emit.jp/prog/prog_opt0.html
んーと、ワタシもくだんのサイトを見て局所変数を多用するようになったクチなんですが。。。で、最適化のあまり可読性の低下を招くのでは???つう話が出たり出なかったりしているわけです。とりあえず、しばらく試してみた感想を述べてみますと、引用先にあるような「コンパイラに意図を伝えて最適なバイナリを吐かせよう」と云うタイプの最適化をすることで可読性が下がることは無いと思ってます。寧ろ可読性アップ。ちなみに可読性が下がる最適化っつうのは、「AAA後にBBBって処理を行ってるけど、CCCって書くと処理がまとめられてクロック数が下がるぜ」ってタイプだと思う。
馬鹿だった頃は、局所変数とか使ってると無駄なメモリコピーとか起こって遅くなると思ってたのですが、局所変数は多すぎなければレジスタに置かれて高速に処理されるので寧ろ早いってわけです。と、云うわけで、局所変数はガスガス使った方がいいみたいです。
さて、他人様のソースを眺めると云うのは、書いてあることがどう云う処理を意図としているかを読み取る作業に他ならないのですが、その中でも変数の意味付けを追っかけると云うのがなかなか大変な作業を占めています。
int a;
なんて書かれた日には、変数aは座標を表しているのか、なんらかの演算結果を格納するためのものなのか、ループカウンタなのか、まったく判りません。
int length;
としてくれれば、lengthって「あ、なんらかの長さなのか?」と多少特定することができます。こんな具合に、使われ方なんて無限にある変数を、名前から、代入されている値から、文脈から、作ったひとの性格から、ありとあらゆる情報を駆使して特定して絞り込んでゆく作業になるわけです。
さて、
class Str { char mStr[MAX]; int mLength; }; Str gStr;
なんてのがあったとして、
void func() { int hoge = gStr.mLength; : : }
と書かれた場合はどうなるでしょう。局所変数ってのは、関数func()から抜けると破棄される、つうのがミソで、つまりは「func()の外には影響ありませんよ」と云う判断材料になります。func()の中でいかに踏んだり蹴ったり演算されようとも、外に出てしまえばスッキリ忘れてしまいます。hogeはまあ、なんかの長さを一時的に保持しておく程度のものなのでしょう。
hoge++;
なんてあったとしても、「あ、なんか1を足したかったんだな」なんてものです。これが、
gStr.Length++;
なんて書かれた日には、gStrの(よくわからんが)長さが変わってしまった!なんて大変な事態なわけで、それこそ、関数の外のどこに影響が波及しているなんか想像だにできません。
void func() { int x; for(x=0; x<10; x++) : (処理A) : for(x=0; x<10; x++) : (処理B) : }
と
void func() { { int x; for(x=0; x<10; x++) : (処理A) : } { int x; for(x=0; x<10; x++) : (処理B) : } }
なんてのも雲泥の差で、上みたく変数の使いまわしなんてのはもってのほかです。一応、処理Bの前で初期化をしているようではありますが、やはり死んでない以上は処理Aと処理Bの間になんらかの関係があるのかもしれない…?という不安がぬぐえません。もう、全く独立の関係であるというなら、きちんとブロックで切って明示しておいた方が誤解が減るでしょう。
つまり、プログラム言語の曖昧さによるブレをなくして、コンパイラに処理の意図を伝える最適化は、曖昧さによるブレをなくして後でソースを読むひとに処理の意図を伝えることに他ならないのです。だから、(コンパイラに意図を伝える意味での)最適化は可読性の向上につながると思います。
ただ、コンパイラは言語の仕様を当然完璧に知っているので、言語仕様でソースを可能なだけ絞り込めばそれだけ正確に意図が伝わりますが、ソースを読むひとは必ずしも言語仕様を熟知しているわけではないので、あまりにもマニアックな仕様での絞込みをすると、意図が伝わらないことがあります。この辺の温度感覚はさすがにちょっと考慮しないといけません、が。