前置き
前置き1
本記事は次の記事へ強く影響を受けております。
上で書かれているようなnull安全について少し別の角度から整理することを目的としてこの記事を書きましたが、上記の記事を理解しているならば以下の内容は蛇足かもしれません。
前置き2
nullに当たる概念の名称は言語によって微妙に異なりますが(例: Scala → None, Swift → nil)、以下では押し並べてnullと表記します。
本記事の目的
以下ではnull安全の共通理解を助けるためにnull安全と関係した3つの型について定義・説明します。
null安全に関係した3つの型
1. null非許容型1
以下の特徴を持ちます:
- 宣言あるいは推論された型の代入を許容する
- nullの代入を許容しない
Javaのプリミティブ型、TypeScriptのデフォルトの型などがこれに当たります。
int a = 10; // OK
int b = null; // コンパイルエラー
a: string = 1; // OK
b: string = null; // コンパイルエラー
2. null許容非安全型1
以下の特徴を持ちます:
- 宣言あるいは推論された型の代入を許容する
- nullの代入を許容する
- nullチェックやパターンマッチなしに元の型の属性やメソッドへアクセス可能(ただし中身がnullだった場合は実行時例外が発生する)
Javaの参照型などがこれに当たります。
MyClass a = new MyClass(); // OK
MyClass b = null; // これもOK
a.method1(); // OK
b.method1(); // NullPointerExceptionが発生
3. null許容安全型1
以下の特徴を持ちます:
- 宣言あるいは推論された型の代入を許容する
- nullの代入を許容する
- nullチェックやパターンマッチなしに元の型の属性やメソッドへアクセスできない
Kotlinのnull許容型、TypeScriptのnull共用型などがこれに当たります。
val a: String? = 1 // OK
val b: String? = null // OK
b.length // コンパイルエラー
if (b != null) { b.length } // OK
比較表
型名 | nullを許容 | nullチェックなしに 属性やメソッドへアクセス |
実行時例外が 発生する危険が |
代表例 |
---|---|---|---|---|
null非許容型 | しない | n/a | ない | Javaのプリミティブ型 TypeScript |
null許容非安全型 | する | できる | ある | Java, C#の参照型 |
null許容安全型 | する | できない | ない | Kotlinのnull許容型 TypeScriptのnull共用型 |
言語仕様の観点から見たnullとnull許容型
nullというものは言語仕様の中でも大抵特別に扱われています。
というのも言語処理系としては宣言された型の値のみの代入を許容する(つまりnull非許容型)が最も自然だからです。あえてnull許容型を言語デフォルトとして実装している2のはプログラマーの利便性などを考えた拡張だと言えます3。
ScalaやHaskellなどでは型階層を工夫することでnullを単なる1つの値や型として表現しています。そうすれば言語仕様上nullを特別扱いする必要がないためです。
言語デフォルトの型のトレンド
2012年頃までは多くの産業向き言語でnull許容非安全型がデフォルトの型でした。
C, C++, C#, Java, Objective-Cなどがそれに当たります。
しかし、null許容非安全型を使うことの危険性が広く認知されたことにより2012年頃を境にデフォルトの型がnull許容安全型であるような言語が開発され徐々に普及するようになりました。代表的なものにKotlin, Swift, TypeScriptなどが挙げられます。
最近良く聞くようになったnull安全とは何なのか
端的に書くと、null許容非安全型の利用をやめて実行時例外が発生する危険をなくそう、というものになります。
しかし、JavaやObjective-C, C#などでは言語デフォルトの型がnull許容非安全型であるためnull許容非安全型を使わないことは不可能です。
そのためKotlinやSwift, TypeScriptなど言語デフォルトの型がnull許容安全型であるような言語への移行が2019年現在進んでいます。