型はどこまで意味を表現できるのか?
前回で挙げた問題をまとめると、
型は単なる
データの解釈
ではなく
意味の表現
である必要がある。
求められている役割:
- データ解釈
- 意味の区別
- 性質の表現
- 制約の表現
- 関係性の表現
- 不変条件
- 状態
- 失敗可能性
つまり
型 = データ + 意味
なぜ実現が難しかったのか
これを実装するのは簡単ではなかった。
意味を型に含めるためには、多くの言語機能が必要になる。
- generics
- 代数的データ型
- 型推論
- trait / interface
- パターンマッチ
- ゼロコスト抽象化
- 安全なメモリモデル
これらは比較的最近整ってきた。
古い言語では次のような要素が優先されていた:
- 実行速度
- ABI互換性
- 実装コスト
- コンパイラの単純さ
その結果、
意味は型の外へと追い出されることになった。
例:
コメント
int user_id; // user id
命名
userId
ドキュメント
README
つまり
型だけでは意味を表現しきれなかった
Rustのアプローチ
Rustは
意味を型に含める
ことを重視して設計された。
例えば:
所有権
&T
&mut T
参照の性質が型に含まれる。
状態
Option<T>
値が存在しない可能性が型に含まれる。
失敗可能性
Result<T,E>
成功か失敗かが型で表現される。
意味の区別
struct UserId(String);
struct ProductId(String);
同じ構造でも意味が区別される。
性質
trait Clone
trait Hash
振る舞いが型に含まれる。
不変条件
NonZeroUsize
成立しない状態を型レベルで排除できる。
ここでは
意味が型の一部になっている
まとめ
プログラミングとは
ビット列とその操作に意味を与えること
である。
型はそのための最小単位の抽象化であり、
歴史的には
データの解釈
↓
意味の表現
へと役割が拡張されてきた。
Rustは
意味を型に統合する
方向へ強く進んだ言語である。
そして、Rustは長年求められた型を実装した素晴らしい言語だとわかる