人のコードみてて思い出した話。
いわゆる「三値問題」というのかな。「好き/嫌い」という二元論は「真/偽」で事足りるが、「どちらでもない」はどう表現すれば良いのか、て話。
かくも実世界ではよくご登場の頻出分類問題なんだけれど、これを「プログラミング言語がネイティブに型として」サポートしている例がない。というか「ワタシが知る範囲の言語では」ね。最近だともう知らない言語の方が増えてきちゃってるし。
「プログラミングがネイティブに型としてサポート」がない理由は明らかで、ほとんどの言語が「汎用的な意味での nothing / none」を何かしら提供しているから。つまり bool 型に収めるべき場所に None を突っ込むことで「知らない」を表現出来る、というわけだ。データベースの null も同じく。
ただこれが「C 言語」だと事情が相当に違う。なぜなら、「ポインタで表現しないネイティブ型を NULL には出来ない」から。初心者なんかはやってしまいそうだけれど、以下は全く意味をなしてない:
1 #include <stdio.h>
2 typedef enum _MYBOOL {
3 MYFALSE = 0,
4 MYTRUE = 1,
5 } MYBOOL;
6 int main()
7 {
8 MYBOOL b = (MYBOOL)NULL; /* neautral */
9 b = MYTRUE;
10 return 0;
11 }
そもそも「叱られたからキャストで誤魔化す」という時点でもう 0 点だが、そもそもこれをどう頑張っても、コメントで書いた「neutral」として機能させることは不可能である。だってこれ、「ただのゼロ」、つまりまごうことなき「オレ偽」になるだけだから。三値を表現したくて、結局二値しか表現出来ていない。
だから「汎用的な意味での nothing / none / …」として NULL を使うというのは実は限定されてしまう、ということ。これだったら出来るんだもの:
1 #include <stdio.h>
2 typedef enum _MYBOOL {
3 MYFALSE = 0,
4 MYTRUE = 1,
5 } MYBOOL;
6 int main()
7 {
8 MYBOOL* b = NULL; /* neautral */
9 return 0;
10 }
そういうわけで、「一般的なニーズに即した三値型」は C/C++ では enum で自作するしかなくて、たとえば
1 enum triState {
2 unset = -1,
3 _False = 0,
4 _True = 1
5 };
など。
C 時代から発明されてれば世界は変わっていたのに、というものはいくつか(いくつも?)あるが、一つは bool、もうひとつがこの triState なんじゃないのかなぁ、なんて思うのだ。ほんとこれ、頻出なんだよな。
Python などスクリプト言語でも、確かに C ほどは困らないが、「一切困らない」ということでもない。C 同様に、本来 None はもっと限定的なものであって、「プログラミング的な誤り」を示すものですらあり、むしろその用途にこそとっておきたい、None は。
データベースで表現するときだって、本来は四値の、「「はいと回答/わからないと回答/いいえと回答」+未回答」の、「未回答を null で、「yes/unknown/no」を triState で」、なんてやりたいでしょう? (ワタシが参加したプロジェクトでは、「不明フラグ」なんてのが頭痛の種であった。)
まぁ今更言っても仕方がないことではあるのはわかっていつつではあるんだけどさ、必要と感じるたびに、毎度同じことを考えるのであった。
ちょっと面白い話が残ってたので追記。
上でちょっと言った「不明フラグ」なんだけれど、こういうの、経験ない人だと「価値のないデータであることを示すためのもの」と思うかもしれないけれど、これが全然違くて。
たとえば警察向けのシステムを構築していることを想像してみて欲しい。そして例えば「職務質問管理データベース」なんてのを作ろうとしているとする。例えばこんなだ:
- 対象者の職業質問への態度
- 誠実
- 回答に疑問あり
- 不明
このケースにおける「不明」は、「要再職質」というトリガーになりうるかもしれない、だろ? 不明が重要である状況も多いのだ。
ワタシが参加したのはさすがに警察向けシステムではないけれど、実はそれにちょっと似た、「あるリスク管理にかかるシステム」だった。だから「不明だからゴミ」は全く通用しないシステムだった。むしろリスク管理的には「不明」こそが最大の「何かしらのアクションを起こすべき」な重大データだったりするのであった。