論理値の比較

いっかい GDNJ でも書いたネタだけど、私の場合...

  bool value = ...;
  if (value != false)
  {
    ....
  }

みたいなコードをみかけると、思考が2〜5秒停止する。*1if の中に入る条件を頭で瞬間に理解できないのだ。

  bool value = ...;
  if (value)
  {
    ....
  }

当然、上のようなら瞬間的、逆に、

  bool value = ...;
  if ((value == false) != false)
  {
    ....
  }

なんてレベルになると停止時間が5秒確定で、

  bool value = ...;
  if (value == false && (value == false) != false)
  {
    ....
  }

なんてレベルになると、括弧付けの書き方の差異まで含めてたっぷり停止というか、一瞬思考破棄してしまいます。また、(現在の仕事環境のメンバーに関していえば)このようなコードを書いている人は、

  bool value = ...;

  return value != false ? true : false;

というようなコードも頻繁に記述されています。
どうしてこんなコードが量産されているのか、ちょっと不思議におもったので考えてみましたが、もしかするとC言語によるプログラミング経験の高い人が、このような傾向になるのではないかと思うようになりました。具体的に問い詰めたわけではないのですがが、「この人は Java やってるな」とか、なんとなくわかるんですよね。*2 それで、上のような論理値の比較をするのは、どうもC言語系な人っぽいですね。
C言語では、明確な論理値型というものは存在せず、論理演算は非0(真)か0(偽)という判定を行われます。これに対して PascalJava では論理値を保持する bool や Boolean のような型があり、真偽の判定は論理型で扱います。*3 そして、このような論理型を保有する言語の多くは、論理判定にC言語などと互換性のあるゼロ判定を許容しないものが多いという特徴もあります。
では、なぜC言語などを利用していると != false や == false といったコードを記述するようになるのでしょうか? これは真値が !0 であるため、どのような値と比較したらよいかわからないためではないかと思います。たとえば、OLE/COM の世界では真偽判定の真値は -1 を使用することが多いのですが、Windows API の世界では 1 を利用することが多いです。*4これらには TRUE というマクロ*5が割り当てられていることが多いので、真値との一致判定を行うには、

  int boolean_value = func(...);
  if (boolean_value == TRUE)
  {
  }

というような記述になってしまうわけですが、func() の実装が TRUE を -1 と定義し、この利用する側では TRUE を 1 と定義していたとしたら、この判定式は失敗することになります。*6 これに対して、FALSE と比較する場合、TRUE が -1 でも 1 でも問題ない動作をするわけで、「論理比較は FALSE と比べる」というコーディングが身に染みてしまうんじゃないか?と思ったわけです。
1998年頃の apache httpd server は、上記のようなコードが一杯でして、外部モジュールの関数が返す真偽値をとことん 1 と比較していました。このため cygwin 環境でビルドされた apache httpd server に Visual C++Borland C++ などの win32 native 向けな環境でビルドしたモジュールを食わせると、関数の戻り値の比較判定でバンバン失敗しておりました。

*1:かかる時間は変数名の命名次第といったところ

*2:Java な人は、自分で .GetEnumerator() して while ( .MoveNext() ) するのが大好きです…たぶん(笑)

*3:C++ にも bool という型がありますが、C++ の bool は論理型ではなく整数型であり、C++ の論理評価はC言語と同じく !0 と 0 で判定しています。if 文など論理判断において bool 型を評価すると、Integral Conversion によって整数値としてゼロ判定されます

*4:DirectShow なんかのヘッダファイルでは、この区別のため TRUE とは別に OLE 用に OATRUE というマクロを定義しています。

*5:C言語では定数は定数宣言ではなくプリプロセッサマクロで名前が付けられるのが一般的

*6:個人的には、この場合 if (boolean_value) と書いて欲しいんですが…。