視点がさまよっているif文,for文は読みにくい2


リファクタリングが必要になってC++のソースコードを読んでいる。
数直線での順序が理解しやすいのは私も経験しています。

わかりにくいソースコードの1つの要因は、ソースコードで変数に着目する際に視点がさまよっていることであることに気づいた。
for文の場合、制御変数にしたがって視点が動いていく。その制御変数に沿った視点で現象を記述していくことで現象が理解しやすくなる。記述の複雑度があがったときにどう考えるのがよいだろうか。

単独のif文での記述の問題ではなく、for文という制御の中心の変数が、文脈の主語になっているような状況では、
その主語が個々の文の中で埋没しないような記述の仕方をしたほうがよいのではないかという問題提起です。
既に十分に明快に記述の場合には、「そんなのどっちで書いても同じじゃないか」となると思うのです。
ところが、実際の私が見るコードでは複雑度がもっと上がってしまい、次のような記述になってしまうことが多いのです。
前回の例よりも複雑な事例を示します。
 
よいと思われる例 1


const double a = 1.0;
double f(double x);

for(int x = 0; x < n; x++){
    if(f(x) > a){
        doSomething(x);
    }
}

推奨しかねる例 1

const double a = 1.0;
double f(double x);

for(int x = 0; x < n; x++){
    if(a < f(x)){
        doSomething(x);
    }
}

よいと思われる例 2


const double a = 1.0; 
bool isBar(double x);

for(int x = 0; x < n; x++){
    if
    if(f(x) > a){
        doSomething(x);
    }else if(isBar(x)){
        doSomething2(x);
    }else{
        ;
   }
}

推奨しかねる例 2

const double a = 1.0;
bool isBar(double x);

for(int x = 0; x < n; x++){
    if(a < f(x)){
        doSomething(x);
    }else if(isBar(x)){
        doSomething2(x);
    }else{
        ;
    }
}

このような状況のコードを読むことになると、着目している変数(これが、いわば文の主語)が安定している記述になるほうがいいのではないかという提案です。ここで着目している変数ですから、定数は文の主語にはなりません。
コメントで指摘されているように、比較対象が、定数かどうかで記述の仕方を変えることを指摘している
The Order of Arguments in Conditionals
の考えに私は同意します。

比較演算の左辺式は文の主語である。

  x > a;

x is greater than a.
という文であると考えます。

代入式new[i] = a[i];では、左辺値が主語と考えられる。

// new[i]が [a[i], b[i]]の範囲になるようにクリッピングする。
for(int i=0; i<n; i++){
    if(new[i] < a[i]){
        new[i] = a[i];
    }else if(new[i] > b[i]){
        new[i] = b[i];
    }
}

数直線で考えるのがよいと思われる例

if( (-1.0 <= x) && (x < 1.0)){
    doSomething(x);
}

推奨しかねる例

if( (x >= -1.0) && (x < 1.0)){
    doSomething(x);
}

扱っている対象のソースコードの対象が、数直線で考えるやり方で十分に理解しやすいものである限りは、
それでいいと思います。
ここで述べたいのは、コードの記述の複雑度が上がってしまって理解しくくなるときには、ソースコードを文章としてとらえ、その主語は何であるのか考えた記述をする方法があるという提案です。