"i"禁止
昨晩、組み込み系で働いてる友人と話していて、「ループカウンタ変数として"i"を使うの禁止」というコーディング規約だという話を聞いた。
前提として、言語はCであった。
ループカウンタを使うのはどんなときだろうか。
最初に思いついたのは配列の内容を順次使用する場合。
for (i=0; i<N; ++i) { printf("%d\n", data[i]); }
この場合、重要なのは配列の意味であろうと思う。この例では、"data"とかいう、何が入ってるんだかまるでわからない名前が問題なのであって、"i"が問題なのではない。"N"もどうかと思うが。
次に多重化する場合。
for (i=0; i<N; ++i) { for (j=0; j<M; ++j) { for (k=0; k<L; ++k) { printf("%d\n", data[i][j][k]); } } }
3次元まで到達するようなプログラムは大抵物理学由来であろう。数式の上で添え字としてi,j,kを使うのはむしろ一般的なので、これは逆にわかりやすい命名だと言えると思う*1。ここでも"data"や"N","M","L"という命名には問題があるだろう。
一方、物理とは関係ないケースでは、2次元が限界ではないだろうか。世の中の様々な事象を分析するのには、ほとんどの場合、状態ベクトルを作って行列で処理するだろう。一変数高次多項式の方程式を作るよりも、多変数一次方程式の方がモデル化しやすいし、固有値や特異値、行列のランクからもわかることは多い。技術者といえど、3階以上のテンソルとなると、途端に難解に感じるのではないだろうか。
というような内容をその場では考えていた。
そのときは訳が分からんと答えたのだが、実際どういうことなのか、考えてみる。
まず、配列内容を回すだけの場合、ループカウンタを使う必要は無い。特に組み込み用途であれば、ポインタを使うだろう。
int * p = data; while (*p != END) { printf("%d\n", *(p++)); }
この場合も、"p","data","END"といった変数名はあまり適切じゃなさそうだけど、とりあえずループカウンタの話ではない。これは、要するにC++でstd::vectorの添え字でループ回すくらいならイテレータ使えよ、という話と同じ。
つまり、Cでループカウンタを使う必要がある、ということは、ループ回数自体に意味があるケース、ということになるだろう。
for (i=0; i<N; ++i) { printf("%d\n", i); }
そりゃ"i"は使用禁止ですってことにもなる。ループの終了条件を見れば、"i"が何を意味しているのかはわかるだろうが、局所的に見た時に、「このprintfは何を出力しているのか」がわからない。"i"ではなく、それなりに意味のある変数名にすべきだろう。
*1:本来は逆に、ループカウンタに"i"を使うという習慣自体が、FORTRANの仕様(変数名の先頭がI〜Nのものは暗黙的に整数型)から来ていて、恐らく物理・化学方面の利用を想定したものだと思う。