色々なオブジェクト指向言語の型システムを比較してみた

## はじめに

オブジェクト指向言語を対象に、型に関する情報をまとめてみました。
誤り、改善箇所がありましたらコメントいただけますと幸いです。

公開当時（2020/12）の情報を基に書いています。

## 比較表

|言語名           |登場年 |[①検査タイミング](#検査タイミング)|[②指定方法](#指定方法)|[③互換性の確認方法](#互換性の確認方法)|
|-----------------|-------|--------------------|------------------------|--------------------------------------------------|
|Smalltalk        |1980   |動的                |暗黙的                  |ダックタイプ的                                    |
|Ada              |1983   |静的                |明示的                  |名前的                                            |
|C++              |1983   |静的<br>ときどき動的|明示的<br>ときどき暗黙的|名前的<br>ときどき構造的                          |
|Objective-C      |1984   |静的<br>ときどき動的|明示的<br>ときどき暗黙的|名前的<br>ときどきダックタイプ的                  |
|Eiffel           |1985   |静的                |明示的                  |名前的                                            |
|Object Pascal    |1986   |静的                |明示的                  |名前的                                            |
|Perl             |1987   |動的                |暗黙的                  |ダックタイプ的                                    |
|Python           |1990   |動的                |暗黙的<br>ときどき明示的|ダックタイプ的<br>ときどき名前的                  |
|Lua              |1993   |動的                |暗黙的                  |ダックタイプ的                                    |
|Java             |1995   |静的                |明示的<br>ときどき暗黙的|名前的                                            |
|PHP              |1995   |動的                |暗黙的<br>ときどき明示的|ダックタイプ的<br>ときどき名前的                  |
|JavaScript       |1995   |動的                |暗黙的                  |ダックタイプ的                                    |
|Ruby             |1995   |動的                |暗黙的                  |ダックタイプ的                                    |
|C#               |2000   |静的<br>ときどき動的|明示的<br>ときどき暗黙的|名前的<br>ときどきダックタイプ的                  |
|Visual Basic .NET|2001   |静的<br>ときどき動的|明示的<br>ときどき暗黙的|名前的<br>ときどきダックタイプ的                  |
|Scala            |2003   |静的                |明示的<br>ときどき暗黙的|名前的<br>ときどき構造的                          |
|D                |2007   |静的<br>ときどき動的|明示的<br>ときどき暗黙的|名前的<br>ときどき構造的                          |
|Go               |2009   |静的                |明示的<br>ときどき暗黙的|構造的<br>ときどき名前的<br>ときどきダックタイプ的|
|Rust             |2010   |静的                |明示的<br>ときどき暗黙的|名前的                                            |
|Kotlin           |2011   |静的                |明示的<br>ときどき暗黙的|名前的                                            |
|Dart             |2011   |静的<br>ときどき動的|明示的<br>ときどき暗黙的|名前的                                            |
|TypeScript       |2012   |静的<br>ときどき動的|明示的<br>ときどき暗黙的|構造的                                            |
|Swift            |2014   |静的                |明示的<br>ときどき暗黙的|名前的<br>ときどき構造的                          |

***

## ①検査タイミング

<sup>[比較表にもどる ↩](#比較表)</sup>

### 📝 分類

#### ⅰ. 静的な検査 *static checking*

実行前に検査する方式。

#### ⅱ. 動的な検査 *dynamic checking*

実行時に検査する方式。

***

### 🔦 特徴的なケース

#### ケース1. オブジェクトだけ実行時に検査する

該当：Objective-C

Objective-Cはコンパイル型言語なのですが、オブジェクトの型だけは実行時に決定します。

#### ケース2. コンパイル時に決まらない分は実行時に検査する

該当：Dart, TypeScript

静的な検査で型が決まらなくてもエラーにせず、実行時の検査で問題があればそのタイミングでエラーとしています。

***

## ②指定方法

<sup>[比較表にもどる ↩](#比較表)</sup>

### 📝 分類

#### ⅰ. 明示的な指定 *explicit specification*

プログラムの要素に対して特定の型を指定する様に記述する方式。

```java:Java
// int型を明示している
int number = 123;
```

#### ⅱ. 暗黙的な指定 *implicit specification*

明示的な指定の反対。特定の型を指定しない方式。

```ruby:Ruby
# 型を明示しない
number = 123
```

***

### 🔦 特徴的なケース

大まかには下記の傾向があります。

- 検査が静的なら明示的な指定をする
- 検査が動的なら暗黙的な指定をする

が、そう単純でないケースも有ったので紹介します。

#### ケース1. 検査は静的だが型推論で一部の指定を省略できる

該当する言語：C++, Java, C#, Scala, D, Go, Rust, Kotlin, Dart, TypeScript, Swift

```scala:Scala
// 型の指定は無いが、123を代入してるのでintと決定する
val x = 123
```

#### ケース2. 通常時の検査は静的だが、専用の構文で指定を省略すると検査が動的になる

該当する言語：C++, C#

```c#:C#
// 型の指定は無いが、実行時に動的に決定する
dynamic number = someNumber;
```

#### ケース3. 検査は動的だが明示的な指定ができる

該当する言語：Python, PHP

```php:PHP
// 型の指定に基づき、代入可能か実行時に検査する
public int $number = 123;
```

#### ケース4. 明示的な指定を強制するか選べる

該当する言語：Visual Basic .NET

```vb:Visual&nbsp;Basic&nbsp;.NET
Option Strict On ' 明示的な指定を強制する設定

' 中略

Dim number As Integer = 123
```

***

## ③互換性の確認方法

<sup>[比較表にもどる ↩](#比較表)</sup>

### 📝 分類

#### ⅰ. 名前的な互換性 *nominal compatibility*

名前によって決める方式。

```java:Java
// User型が期待されている。右辺も同じくUser型だから代入可能
User user = new User();
```

#### ⅱ. 構造的な互換性 *structural compatibility*

静的な検査時の構造によって決める方式。

```ts:TypeScript
interface User { name(): string; }

// Userと同じ構造が期待されている。右辺が `name(): string` をもつから代入可能
const user: User = { name: () => "山田太郎"; }
```

#### ⅲ. ダックタイプ的な互換性 *duck type compatibility*

動的な検査時[^1]の構造によって決める方式。

***

### 🔦 特徴的なケース

#### ケース1. 通常は「名前的」だが、テンプレートを使うと「構造的」になる

該当：C++, D

通常時は「名前的」ですが
次の様にテンプレートを使うと「構造的」になります。

```cpp:C++
// 引数には`std::string name()`の構造が期待されている
template<class T> std::string user_name(T user) {
   return user.name();
}
```

#### ケース2. 通常は「構造的」だが、比較対象同士の型が名前をもつなら「名前的」にもなる

該当：Go

```go:Go
// `Name() string`の構造が期待されている
var user interface { Name() string }

// Userと同じ構造が期待されている
// ただし、同じ構造でもUser以外の名前の型なら代入できない(匿名なら代入可)
var user User
```


#### ケース3. 対象の型に応じて異なる方式を使い分ける

該当：Swift

Swiftでは

- 関数とタプルだけ「構造的」
- 他は「名前的」

このように方式を使い分けています。

***

## 参考文献

Pierce, B. C., & C., B. (2002). Types and programming languages. MIT Press.

バートランド・メイヤー. (2008). オブジェクト指向入門: 方法論・実践.

増井敏克. (2017). プログラミング言語図鑑: プログラミング言語の現在・過去・未来...知ればもっと楽しめる!

Comparison of programming languages by type system. (2016, May 22). - Wikipedia. Retrieved December 24, 2020, from https://en.m.wikipedia.org/wiki/Comparison_of_programming_languages_by_type_system

Type system. (2003, March 22). - Wikipedia. Retrieved December 24, 2020, from https://en.m.wikipedia.org/wiki/Type_system

なぜGoはDuck typingを採用していると言えるのか、データ構造から詳しく解説してみた. (2020, January 26). Qiita. Retrieved December 24, 2020, from https://qiita.com/ttiger55/items/ecf6765847faacf9a60b

[^1]: ダックタイプ（ダックタイピング）という語は、「動的な検査時」に限定しない意味で使うことも有る様です。が、曖昧さの無い他の言葉が見つからなかったので、採用しました。