社内で、人のプルリクを眺めていたら、新人と2年目との、不思議なやりとりがあった。
元々、こんなコードがあった。
if (isHoge()) {
foo = something_value;
} else {
foo = another_value;
}
別の方法でもfooを指定できるように改造することになったため、新人は以下のようなコードを書いた。
if (isGuruguru()) {
foo = guruguru_value;
} else {
if (isHoge()) {
foo = something_value;
} else {
foo = another_value;
}
}
そこに、2年目くんから「元々の処理を変更しない方がいい。ネストを深くしない方がいい」という物言いがついて、コードはこのように変更された。
if (isHoge())) {
foo = something_value;
} else {
foo = another_value;
}
if (isGuruguru()) {
foo = guruguru_value;
}
これはものすごくよくない。
今回のやりとりを知らずに、このソースを見た人は、isGuruguru
の部分だけを追いたかったとしても、関係ないところ読まされる上に「なんか、fooを2回代入してるけど、これ意味あんのかなぁ?」という疑問を抱きながら生きることになる。そういった人生を他人に送らせるべきではない。
最初に新人が書いたコードだが、gitのdiffで見ると、とてつもなく複雑な変更を加えているように見える。
-if (isHoge()) {
- foo = something_value;
+if (isGuruguru()) {
+ foo = guruguru_value;
} else {
- foo = another_value;
+ if (isHoge()) {
+ foo = something_value;
+ } else {
+ foo = another_value;
+ }
}
けれど、よくよく見ると、これは新たにif else構文を1個付け加えて、元あったコードをelse節にぶちこんでるだけだ。
これは git diff -w
のように、-w
オプションを付けてdiffを取ると分かりやすい。
+if (isGuruguru()) {
+ foo = guruguru_value;
+} else {
if (isHoge()) {
foo = something_value;
} else {
foo = another_value;
}
+}
ところで、C言語の規格書にはelse if
構文はない、という話を聞いたことがあるだろうか。
http://kikakurui.com/x3/X3010-2003-01.html より、規格を引用する。
6.8.4 選択文
構文規則
選択文:
if ( 式 ) 文
if ( 式 ) 文 else 文
switch ( 式 ) 文
意味規則 選択文は,制御式の値に応じて幾つかの文の中から一つを選択する。
選択文はブロックとする。そのブロックの有効範囲は,それを囲むブロックの有効範囲の真部分集合とする。各副文もブロックとする。そのブロックの有効範囲は,選択文の有効範囲の真部分集合とする。
6.8.4.1 if 文
制約 if 文の制御式は,スカラ型をもたなければならない。
意味規則 両形式とも,式の値が 0 と比較して等しくない場合,最初の副文を実行する。else 形式の場合,式の値が 0 と比較して等しいならば,2 番目の副文を実行する。ラベルを通して最初の副文に制御が到達した場合,2 番目の副文は実行しない。
elseは,構文規則で許される if のうち,その else の前で最も近い位置にある if と結び付く。
6.8.4.2 switch 文
...
見て分かる通り、else if
という構文はない。では、C言語でelse if
を書くとコンパイルエラーになるのか。いいや、ならない。
C言語においてはelse if
とは、if (式) 文 else 文
の、二つ目の「文」に、別のif
文を持ってきているものとみなされる。
文は {}
で囲うことができるので、例えば
if (式) 文
else if (式) 文
else 文
は、こう書くこともできる。
if (式) 文
else {
if (式) 文
else 文
}
つまり、この2つの書き方は等価なのだ。
これはあくまでC言語の話で、例えばPythonなどでは、
if 式:
文
else: if 式:
文
のような書き方はできず elif
といったキーワードが必要になるが、else
の中にif
文だけを書くのと、if...elif...else
構文を使うのが等価であることには変わらない。
if 式:
文
else:
if 式:
文
else:
文
if 式:
文
elif 式:
文
else:
文
elif
を使った方が断然見やすい。
ところで、話を元に戻そう。
新人が書いたコードを見てほしい。
if (isGuruguru()) {
foo = guruguru_value;
} else {
if (isHoge()) {
foo = something_value;
} else {
foo = another_value;
}
}
あ、else
の中に if
文が入ってる!
なので、これはこのように書ける。
if (isGuruguru()) {
foo = guruguru_value;
} else if (isHoge()) {
foo = something_value;
} else {
foo = another_value;
}