連載:C# 2.0入門

第4回 Findメソッドとnull許容型

株式会社ピーデー 川俣 晶
2007/08/31

null許容型とは何か?

 ここからは、「null許容型」の話題に移る。null許容型とは、null値も扱える値型のことである。

 リスト8に実例を示す。

using System;

class Program
{
  private static void Sample(decimal? 価格)
  {
    if (価格 == null)
    {
      Console.WriteLine("価格はありません。");
    }
    else
    {
      Console.WriteLine("価格は税込み{0}円です。", 価格 * 1.05m);
    }
  }

  static void Main(string[] args)
  {
    Sample(100m);
    Sample(null);
    // 出力:
    // 価格は税込み105.00円です。
    // 価格はありません。
  }
}
リスト8 値型の型名の後ろに「?」を付けるとnull許容型になる

 ここで、「decimal?」がnull許容型の例である。

 メソッドSampleの引数「価格」は、nullが許容されたdecimal型なので、decimal型の値である「100m」と「null」の双方を受け取ることができる。

 その結果として、「価格」は、「価格 == null」という式によってnullかどうかを判定することができると同時に、「価格 * 1.05m」のようなdecimal型の数値計算の対象とすることもできる。

なぜnullを入れたいのか

 さて問題は、なぜnullを許容する必要があるのか……である。

 これまでの、たいていのプログラム言語では、nullの値になることができる整数型や実数型を持っていない。動的な言語では、整数もnullも代入できる変数を宣言することは容易にできたが、それはnullを許容する整数型とは違う。あくまで別の型の値を代入できた……というだけの話である。C#でも、ボックス化の機能を使えば、nullも整数も実数も格納できる変数は容易に確保できた。

 それでたいていの場合、困っていなかった……というのが過去の状況だろう。では、なぜいまになってnull許容型なるものが出てきたのだろうか。

 それには恐らく「美学」としての理由と、「実利」としての理由の2つがあると考える。

■null許容型の美学

 「美学」としての理由は、「参照型と値型が同じように扱える」という理想にありそうだ。だが、そもそも「参照型と値型が同じように扱える」とはどういうことだろうか?

 例えば、C#登場時にJava信者より投げかけられた批判の1つとして、「構造体という機能は存在理由が不明である」というものがある。しかし、構造体の存在意義は「参照型と値型が同じように扱える」という理想を踏まえることで、容易に説明できる。

 Javaが持つ「参照型はユーザー定義できるのに、値型はユーザー定義できない」「参照型はメソッドを持てるのに値型はメソッドを持てない」といった「同じように扱えない」制約を取り払い、「値型であっても参照型と同様にユーザー定義できる&メソッドを持てる」という機能を実現するために必然的に導入されたものがC#の構造体と見ることができる。

 そして、構造体のおかげで、値型、参照型の区別なく、C#では、取りあえずToString()を付ければ文字列型に変換されるなどの楽な扱いが可能になったわけである。

 だが、それでもまだ参照型と値型には決定的な相違が残っていた。それが、nullという値を許容するか否かである。

 参照型の値は、すべてnullが許容されている。例えば、string型の変数にnullを代入することは常に許容されている。しかし、値型の値はすべてnullが許容されていない。例えば、int型の変数にnullを代入することは、常に許容されない。

 このような非対称性があるため、「参照型と値型が同じように扱える」という理想は実現されていない。

 では、すべての値型がnullを許容できるよう、言語仕様を拡張したらどうなるだろうか。結論は簡単で、実行速度の低下や必要メモリ量の増加により、効率的ではなくなってしまうだけである。

 だが、ただ単に値型であるというだけで、参照型とは違ったコーディングを強要されるのも効率がよくない。そのように考えると、すべての値型にnullを許容するのではなく、null許容型という新しい型を導入するメリットが見えてくるだろう。

 ちなみに、null許容型を導入しても、まだ参照型と値型は完全に同じに扱えない部分が残る。それらの相違は、例えば継承やコンストラクタなどに見られる。それらも含め、完全に同等にすべきか否かはまた別の問題である。

■null許容型の実利

 さて、「美学」の理由はこのあたりして、「実利」の理由について語ろう。こちらの方が、おそらくは重要だろう。

 プログラム内部では、整数型は常に整数だけを扱う型として存在し、nullという値のことなど考えないことが多い。その方が効率が高いし、分かりやすいからである。

 しかし、プログラムの外部に目を向けると、必ずしもそうではないことが分かる。例えば、RDBではNULL値を許容する整数フィールドなどを容易に作成でき、それが便利に活用されている。XMLでも、内容に整数を記述する要素がオプションとしてスキーマ定義されていて、整数が記述されているXML文書と、整数が記述されていないXML文書が混在していることも珍しくはない。

 そして、そのようにして用意されたデータをプログラムに取り込む場合、はたと困ってしまうわけである。

 例えば、筆者がXML文書を読み込む際によく使うテクニックは、XML文書に要素が存在しないときに「記述されていたと仮定するデフォルト値」を用意し、それを補う方法である。これによって、int型変数への値の読み込みは完了するが、これでは「デフォルト値と同じ値が書かれていた」のか「書かれていなかったのか」を区別する手段が失われてしまう。

 このように考えると、null許容型の存在意義が見えてくるだろう。

 「値の欠落」が許容された外の世界から値を受け取る場合、値の欠落をnullで表現するとすれば、null許容型がまさにありのままのデータを受けるための最適な型となるのである。


 INDEX
  C# 2.0入門
  第4回 Findメソッドとnull許容型
    1.MATステートメントの思い出/前回に語り残したこと:ForEachメソッドのbreak問題
    2.ForEachだけではない繰り返しメソッド/複数の結果が欲しい場合/偉大なる前進とは何か?/そしてC# 3.0とLINQへ続く
  3.null許容型とは何か?/なぜnullを入れたいのか
    4.null許容型の内部構造/null合体演算子
    5.is演算子の挙動に注意/3値論理型として使用できるbool?型/nullを許容するとパフォーマンスに影響するか?/補足:null許容への批判
 
インデックス・ページヘ  「C# 2.0入門」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間