++C++; // 未確認飛行 C ブログ

http://ufcpp.net/

non-nullable reference type

leave a comment »

何度かこの話だしてるものの。C# に、参照型だけども null が絶対入っていないことを保証する型(non-nullable)はなぜないの?という話。

それなりにしっかりと説明してるブログ記事を見つけたのでリンク:

以下、簡単な日本語解説。

non-nullable?

.NET は元々、値と参照の区別しか持っていなくて、

  • 値型は常に 非 null (non-nullable)
  • 参照型は null を許容(nullable)

でした。

で、.NET 2.0で、Nullable<T> が導入されて、

  • 値型に nullable が増えて、値型は null を許すかどうかを選べるようになった
  • 参照型はやっぱり nullable のみ

という状態。

もちろん、この時点で non-nullable 参照型の導入も検討はされた(上記ブログはその時代の記事)けども、相当厳しいという話。

既定で null

.NET は、パフォーマンス上の理由で、既定値を 0/null/既定値の入れ子 に限定しています。

値型とか配列を初期化した時に、C でいうところの memset(0) するだけでいいように。

C++ なんかだと、デフォルト コンストラクターを持ってる型の配列を作ったりすると、要素の数だけコンストラクターが呼ばれるという仕様があったり。逆に、デフォルト コンストラクターを呼べない型の配列は作れない。バイト配列を確保しておいて、placement new するとか、このコストを避ける方法はあるにはあるんですが。

初期化順序の泥沼

で、non-nullable 参照型を作ろうとしたときに問題になるのが、この既定値問題。上記理由でいったんは必ず null 初期化されてしまう参照型に対して、「null じゃなくなった」っていうことを保証する仕組みが必要で、これが非常に難しい。

  • 親クラスのコンストラクター内で non-nullable 参照型のフィールドを参照とどうなるの?
    • C# の仕様では、自分のフィールド初期化 → 親のフィールド初期化 → 親のコンストラクター → 自分のコンストラクター の順で呼ばれる。
    • 自分のコンストラクター内での初期化では、親のコンストラクターの時点での非 null 保証ができない
  • 静的メンバーの循環参照があるときどうするの?
    • non-nullable な静的フィールドの 非 null 保証しようと思ったら、静的コンストラクター内で初期化するしかないけども。
    • 静的コンストラクターが呼ばれるタイミングは、そのクラスが最初に参照された瞬間。循環参照してしまうと、片方は非 null 保証できない。
  • 配列どうしよう?
    • 先に領域を確保したうえで、for ループで要素の初期化するような用途の場合どうしたものか。
    • 配列の new[] の時点で、要素初期化子みたいなデリゲートを渡すしかないけど、そういう仕様が .NET にはない。

という感じ。

なので、やるなら最初の(.NET 1.0の)時点でやらなきゃいけなかったし、それをやってたとしても結構変な制約がかかったり、パフォーマンスに影響したりしそう。

Written by ufcpp

2012年11月2日 @ 03:50

カテゴリー: .NET, C#

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。