型とは何か?
プログラミングは 0 と 1 自体と、それに対する操作に意味づけを行う営みである。
この意味付けは 抽象化 によって行われる。
この文脈で 型 は最小の抽象化といえる。
型の最も基本的な役割
型に求められる最小の機能は
バイト列をどのように解釈するか
という非常にシンプルなものである。
例えば
01100001
というビット列は
| 型 | 解釈 |
|---|---|
| int | 97 |
| char | 'a' |
| 命令 | オペコードの一部 |
| struct field | 構造体の一部 |
となる。
つまり
型とはバイト列の解釈規則
である。
この段階では型はまだ「意味」を扱っていない。
次に求められたもの:関係性
プログラムが大きくなるにつれて、
型同士の関係
を表現したくなった。
典型的なのが is-a 関係である。
Dog is an Animal
OOPではこれを継承によって表現した。
class Animal {};
class Dog : public Animal {};
ここで表したいのは
概念同士の関係
である。
継承問題:意味がレイアウトに引きずられる
しかし継承の実装は
メモリレイアウトの互換性
に依存している。
Derived が Base として扱える理由は
先頭のメモリ構造が一致しているから
である。
つまり
意味的関係
Dog is Animal
を
データ配置
Dog の先頭が Animal と同じ
で表現している。
ここに問題がある。
継承には様々な問題が知られている:
- LSP違反(Square問題)
- fragile base class problem
- 多重継承問題
- constructor問題
- has-a と is-a の混同
これらの共通点は
関係性の表現がメモリ構造に依存している
という点である。
つまり
型の意味がデータ配置に制約されてしまう
型に「意味」を持たせたいという要求
サービスが大きくなるにつれて、
型には単なる構造以上の役割が求められるようになった。
例えば:
意味の区別
UserId
ProductId
構造は同じでも意味は異なる。
失敗可能性
Java の checked exception:
void f() throws IOException
ここで表したいのは
この処理は失敗する可能性がある
という意味である。
状態
値が存在しない可能性
null の導入:
String s = null;
性質
Hashできる
Cloneできる
比較できる
これまでの問題点
従来の言語では
意味が型の外に書かれることが多かった
例:
コメント
int user_id; // user id
命名
userId
ドキュメント
README
つまり
人間の理解に依存していた
では求められる型の役割とRustの回答はどのようなものだったのだろうか?
>>> next