MicrosoftでC#のプログラムマネージャを務めるMads Torgersen氏はC# 7の参照への選択型の導入についての提案を公開した。選択型はC#を安全にしnull参照例外を発生しにくくする。Torgersen氏曰く、C#はnull値を参照できるがゆえにnull参照例外が猛威をふるっている。
C#はstruct
をベースにしたnull許容値型を提供しているが、class
をベースにした参照型には提供していない。後付けで既存の言語に選択型を導入するのはとても複雑なため、Torgersenは、“水も漏らさない”完璧な仕組みを提供するのではなく、nullを参照する可能性のあるコードを検知し、警告する仕組みにした。
この新しい提案では、既存の参照型T
は以下の要件になる。
T
は非null許容型を表す。T?
はnull許容の参照型を表す- 以下の条件の時、コンパイラは警告を出力する。
- null許容の
T?
型の参照が外れている、または非null許容型に変換される場合 - 非null許容型の変数に
null
/default(T)
が割り当てられる場合 - null許容参照がnullにならないことをフロー分析で検出した場合
- コンストラクタが処理を戻す前に非null許容参照に割り当てをしない場合
- 非null許容参照がコンストラクタ内で割り当ての前に使われる場合
- null許容の
一方、非null許容型の配列が初期化時のnull要素を維持していないことを保証する方法はない。
C# 6で導入されたnull条件演算子である?.
を使う場合、以下のようになる。
string s;
string? ns = SomeStringMaybe();
s = ns; // 警告を出力
if (ns != null) { s = ns; } // ok
WriteLine(ns.Length); // 警告を出力
WriteLine(ns?.Length); // ok
このような方法は既存のコードを壊さないように考案されたものだが、コンパイラの振る舞いが壊れる可能性がある。現在のC#のT
はnull許容型を表すからだ。それ故、警告をオフにしてC#のバージョンとアセンブリの互換性を確保する仕組みを追加で提供する必要がある、とTorgersen氏はいう。
非null許容型であるT
がnullを含むことができるようになっている点は重要だ。これは、互換性を考慮したからであり、nullが割り当てられた場合は警告を発する。この方式は他の言語と大きくことなる。例えば、Swiftの選択型やHaskellのMaybeでは、選択型はベースの型のある種のラッパーと見ることができる。
この提案にはさまざまな反応があった。T
の意味を再定義することを恐る声や、既存のコードベースから大量の警告が生まれるため、警告の意味がなくなってしまうのではないかという指摘もあった。非null許容型はT!
などT
とは違うもので表現したほうがいいというアイディアを示す人もいた。しかしこの方法では、既存のコードベースに利点がない。非null許容のメリットを享受するためにリファクタリングされるべきコードベースにも関わらずだ。この提案を受け入れ、“strict”モードでnull許容型が効率的にoption<T>
でラップされるような仕組みを求める声もあった。