あるところで紹介されたリンクを辿っていったところ、面白いものに出会いました。
つまり、RDBでNULL値を許すと問題が多いので、できるだけNULLを使わないようにしましょう……という話です。
これを見て、「あっ」と思ったのは、厳密な意味で同じではないものの、私もC#プログラミングでnullの可能な限りの追放を試みていたからです。しかも、何年も前から。
実際、りすと亭のソースには、存在しないことをnullではなく空文字列で示す文字列型の値などがゴロゴロしています。
以下、C#におけるnull追放について、個人的な感想文を書きます。
nullの害 §
C#では、オブジェクト参照の値はnullを取ることができます。
nullに対する参照は、例外になります。
つまり、その値がnullであるかもしれないコンテキストでコードを記述する場合、その値を使った参照を行う前には、値がnullではないことを確認するコードの挿入が要求されます。あるいは、例外を適切にハンドルするコードを記述することが要求されます。
しかし、それは本質的にプログラムの動作そのものを表現するコードとは言い難いものです。つまり、nullに対応することで、ソースコードは本質的に重要ではないコードをより多く含んでしまうことを意味します。
そのようなコードの存在は、ソースコードの分かりやすさを損なうだけでなく、潜在的にバグが入り込む危険性も誘発します。
言い換えれば、nullを使わないような構造に設計すれば、それだけでソースコードの健全性はアップするということです。
無効値とNullオブジェクト(無効オブジェクトの参照) §
nullを使わないためには、null相当の役割を与えた通常値を使うことができます。
たとえば、正の整数を扱う場合に、-1を無効値として使うことがあります。
たとえば、常にゼロではない長さを持つ文字列を扱うときに、長さゼロの文字列を無効値として使う場合があります。(C#では、""ではなくstring.Emptyと書くことで明示的に「空」を示しながら書いたりしている)
オブジェクトに関しては、デザインパターンやリファクタリングで出てくるNullオブジェクトを使います。つまり、nullを使う代わりに、何もしないオブジェクトの参照を使います。この参照を利用しても例外は発生せず、単に何もしないという結果で良ければnullチェックや例外のハンドリングは必要とされません。むしろ、そこでチェック不要になるようにNullオブジェクトを設計することもできる、と言っても良いでしょう。
全てのケースではないものの、かなりの割合のケースでは、無効値やNullオブジェクトを導入することで、nullを排除することができると感じます。そして、それによってソースコードは良くなっていると感じます。
変数にnull値を持たせない §
具体的な事例で説明します。
以下のような構造のコードはよく見かけます。
SomeClass obj = null;
try
{
obj = new SomeClass();
……
}
finally
{
if( obj != null ) obj.Dispose();
}
このケースでは、変数objがnullになる可能性があるので、特に問題がなければ下記のパターンに書き直した方が良いのではないかと感じるわけです。
(ちなみに、両者は厳密に同じ動作ではないことに注意)
SomeClass obj = new SomeClass();
try
{
……
}
finally
{
obj.Dispose();
}
これで、代入が1つ、nullチェックが1つ減りました。
しかし、最大の長所は、本質的に重要ではないコードを減らすことができた結果として、ソースが読みやすくなったことだと思います。
nullable? 欲しいのはnever_nullableタイプだ! §
C# 1.0の参照型の値は全てnull可能(nullable)です。値型はnull可能ではありません。
しかし、C# 2.0には、null可能(nullable)な型が導入され、値型もnullを取る手段が導入されました。
たとえば以下のように、値型のintの後ろにnullableを示す"?"を付けると、nullも代入できる整数ができあがりです。
int? a = 10;
int? b = null;
むろん、できるだけnullを排除しようと試みて、一定の成果を出してきた私から見れば、このような言語仕様の導入は堕落でしかありません。
私が欲しかったのはむしろ逆です。つまり、nullにならないことが保証された参照型です。それは、Nullオブジェクトのテクニックと併用することで、より健全性の高いコードを書くために役立ったのではないか……と思いますが、本当にそれが事実かは試したことがないので分かりません (汗。